Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

This question already has an answer here:

I am an objective-c/iOS apps developer and I was wondering if I perform Unit Tests on my code, how should I go about it?

What is unit test anyway? Ain't I testing a specific part of code while running the whole app itself?

What is its use?

I have read few articles, wikipedia etc. but I am not sure whether unit testing is a time consuming or a time saving process. I know the definition but I am in the dilemma about its purpose.

Plz guide a new bee here. :) Have already gone through the following:

Unit testing best practices for a unit testing newbie

share|improve this question

marked as duplicate by Kilian Foth, Joris Timmermans, GlenH7, MichaelT, Doc Brown Jul 11 '13 at 13:34

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

    
Once you start writing software that is more than a few hundred lines long, you'll see the benefits of unit tests... –  Radu Murzea Jul 11 '13 at 7:52

3 Answers 3

up vote 6 down vote accepted

I am an objective-c/iOS apps developer and I was wondering if I perform Unit Tests on my code, how should I go about it?

Probably by reading some objective-c/iOS-specific unit testing tutorials. I am sure there are many.

What is unit test anyway? Ain't I testing a specific part of code while running the whole app itself?

No, it's testing a specific part of the code ("unit") without all the rest of the app. If the whole app runs, it's an integration test, which is also valuable.

What is its use?

It allows you to test units of code very thoroughly, including special cases (e.g. error handling) that may be hard or impossible to reproduce in the running app. It also gives you tests that run very quickly and thus can be run anytime during development when you need reassurance that you haven't broken anything. This in turn gives you the ability to refactor your code freely, and maintain better quality.

I have read few articles, wikipedia etc. but I am not sure whether unit testing is a time consuming or a time saving process.

Both. Writing the tests consumers quite a lot of time. But overall, it more than makes up for it by catching bugs early and making refactoring easy. The confidence that you can at any time at the press of a button be reassured that the code contains none of the bugs your tests check against is priceless.

share|improve this answer

Unit testing, depending on your background, is more or less counter intuitive. But if you've done it for a while it all seems to fall into place in grand scheme of things related to software development, because of several reasons:

  • Simpler architecture: Unit testing is making sure that small parts of your system or program works. Performing this as a process (with TDD, BDD, whatever) gives you an opportunity to think about your architecture a bit. If the tests are difficult to write, then the system-under-test (SUT) is difficult to use. This notion will hopefully make you stop and think the design of your software through or discuss with someone else if there is a simpler way to do one complex thing.

  • Regression -> Refactor: The major benefit you get from unit testing is that you accumulate regression tests. The value of these tests come when you refactor code, one of the most recurring bugs when refactoring is regressions; that functionality that once worked has stopped working. Once you have tests that tell you when things break, then you know if your refactoring still works or is busted.

  • Stubs/Mocks -> Modular architecture: Many miss, when they start out, that objects have dependencies that should be stubbed/mocked when running unit tests. Being able to mock things out leads to short-term benefit such as faster tests and also long-term benefits such as making sure that your component that you're building can stand on its own. Once you have all components/modules seperate you can make sure when one of them is broken by writing a failing test that exposes the bug and enables you to fix it.

I could go in depth discussion about what good unit testing practices are, but this question thread explains it better: What Makes a Good Unit Test @ StackOverflow. In summary, you should write tests that has business or practical value for you. It is time consuming, but the benefits outweigh the drawbacks if you're doing them in a smart way (ATRIP is a great mnemonic to keep in mind).

To be good at unit testing takes practice... lots of it. The best way to do so is to just dig in and start using a unit testing framework that helps you manage it. For Objective C there are plenty of unit testing frameworks that you can read here: What is the best way to unit test Objective C code? @ StackOverflow

share|improve this answer

What is unit test anyway?

A unit test is a piece of code that takes one unit (usually a method or free function, sometimes an entire class or module), isolates it from the rest of the application, runs it against a known environment, and verifies that it behaves as expected. A typical pattern is "set up, define inputs, run, assert outputs, tear down", where the "set up" and "tear down" steps create the known environment. For any unit that depends on other units, a technique called "mocking" is used, that is, the tested unit is put in a context where the dependencies aren't the real thing, but rather placeholders / stubs. For example, if you test a method that runs against a database class, you don't use the real database class, but a mockup class that ignores its input and returns a hard-coded data set containing what the real one should return.

Ain't I testing a specific part of code while running the whole app itself?

You are, but not in isolation - you are testing the entire application, and when something fails, you often know that it fails, but not where and why. Unit tests tell you that each individual part of your machinery works as specified; testing the whole thing, or larger parts of it, in concert (a.k.a. "Integration testing", "End-to-end testing", or "Simulation testing") is just as important at unit testing, but it serves a slightly different purpose and has a slightly different focus.

What is its use?

Unit testing has several uses:

  • Verification - unit tests should be written such that a passing unit test means that some aspect of the unit works as intended. If all aspects of the unit are covered by tests, you have 100% "coverage", and assuming that the tests accurately reflect the intended behavior, you can be confident that the unit as a whole works correctly.
  • Troubleshooting/Debugging - when things go wrong, you will either have a failing unit test somewhere, which will allow you to pinpoint the problem, or all the tests passes, but things are still going wrong. In the latter case, existing unit tests will help you rule out possible causes and find spec mismatches, and if it turns out that you don't have the kind of coverage you thought you had (e.g., you missed some edge case), you can add a unit test that reproduces the problem, then fix it and use the unit test to verify (see above) that the fix is correct.
  • Regression guards - every unit test you have guards against one possible regression, that is, a change in behavior that is caused as a side effect of another change. If you have good unit tests in place, and you make a change that breaks things elsewhere, your unit tests will tell you. Having complete test coverage will allow you to move faster and make more radical changes with higher confidence.
  • Documentation - since a unit test explicitly tests for one behavioral aspect of a unit, it can serve as a form of documentation: a unit test says "if I use this unit here in such a context and pass it these inputs here, it will produce those outputs". This is valuable information for other developers, and better yet, because it is code that gets validated on a regular basis, it is practically guaranteed to be up-to-date at all times, unlike more traditional forms of technical documentation.
  • Design - there is a whole development methodology (TDD, Test-Driven Design) built around the idea of using automated tests as an integral part of your design process. The mantra is "red, green, refactor": define the feature by writing a test (ideally, just one test) that captures the essence of your intended change; verify that it fails ("red"); change the code just enough to make the test pass ("green") without flipping any other tests to "red"; then refactor the codebase to remove duplication, redundancy and other code smells while still keeping all tests in "green". TDD forces you to work in a highly incremental way, it makes sure you always have near-perfect coverage, and it gets you to focus on one thing at a time. Particular challenges with TDD are that it takes some experience and vision to arrive at an elegant overall design with it (being religious about refactoring helps tons though), and that it doesn't work too well in a highly explorative context where you need to hack away at the code for a while before you even know what the problem is you're trying to solve.

I have read few articles, wikipedia etc. but I am not sure whether unit testing is a time consuming or a time saving process.

The jury is still out on this one, and rigid research in this area is hard if not impossible (how do you do double-blind studies about programming methodologies?) However, there seems to be quite some consensus that automated tests are an investment worth making for almost all projects; a single debugging session can easily eat up ten times the budget spent on writing unit tests, and an unnoticed design flaw can be many times more expensive even. Consider the alternatives:

  • Deploy untested code. This is sometimes a valid choice, e.g. when the code is low-impact (say, a screensaver), or when moving fast is more important than delivering code that works well - in other words, when the risk of deploying a bug is smaller than the risk of not deploying in time. Usually, this is not the case though.
  • Test manually. Manual labor is expensive, and it stays expensive every time you do it. As your codebase grows, so does the manual testing cost per deployment. To make matters worse, manual testing is repetitive work, something that humans are bad at - your testers will make mistakes, they'll raise false positives and miss bugs. Testing manually also takes a lot of time, which means your deployment procedure will take much longer - instead of a nightly build that runs ten thousand automated tests in a few hours, your testers go through a multi-day routine.
  • Formal proof. While it is theoretically possible to do formal proofs of correctness for any given computer program, even very trivial ones are too complicated to do it by hand. This means we need a computer program to do the proving for us, and such tools exist - unfortunately, them being computer programs, they require us to feed them the specifications in a formal language. If you want a complete proof of correctness, you need to give the prover program the entire specification in a formal language - but wait, isn't programming all about encoding requirements in a formal language? Yes it is. So what you really do in the end is write the program twice, in two radically different languages, and then automatically check that the two implementations are equivalent.
  • Rely on the compiler. Some programming languages have powerful type systems and compilers that can check them; in extreme cases, this rules out a large class of possible bugs, and you can leverage such a type system to give you quite some impressive guarantees about your code, for free. Still, you can't encode everything in a type system, so while a good type system can certainly remove the need for a whole truckload of trivial tests ("does this function fail when I pass it null instead of an integer? does it fail when I pass it a string? an object of type UserManager?"), but you will still have a lot of things to test for.
share|improve this answer

Not the answer you're looking for? Browse other questions tagged or ask your own question.