5

I understand how to implement unit tests, I'm just struggling figure out when to use them.

Let's say I have a basic Reminders App. A user can add/edit/delete reminders and view them in a tableview. What parts of the app would I want to set up unit tests for?

mnort9
  • 1,810
  • 3
  • 30
  • 54
  • Your "units of code," such as classes, methods, etc. – Robert Harvey Oct 03 '12 at 18:57
  • Related: [Determining what is a useful unit test](http://programmers.stackexchange.com/q/90217/85530); [When is it appropriate to not unit test?](http://programmers.stackexchange.com/q/66480/85530) – Edward Brey Mar 26 '13 at 11:04

4 Answers4

6

Ideal world answer would say that every line of code you wrote should be unit tested.

But let's forget about that for a moment and move back to real world. Write tests for code that is important and having another line of defense is worth it. In other words, does it make much sense testing constructor that simply assigns value to one field? Most likely not. Is it worth to unit test parser extracting account data from complex XML your client provides? Probably yes.

Where does this difference comes from? Two major reasons:

  • it's less likely that constructor code will suffer from unpredictable changes (vs. much-evolving parser code to meet up with changing requirements/optimizations/refactorings)
  • constructor code is fairly simple and you've wrote such code many times already, tests might not offer you huge advantage in spotting issues; quick glance at such code and you'll be most likely able to tell what's going on (vs. complex XML parser code)

Why making the distinction? Why testing this and not that? Wouldn't it be easier to simply test everything (as ideal world answer would suggest)?

No. Because of time and money constraints. Writing code takes both. And there's only certain amount of money somebody is willing to pay for your product just as there's only certain amount of time he's going for wait for it to be delivered. Some tests are simply not worth it (again, constructor code example). Remember that unit tests are not immune to diminishing returns (having 80% code base covered with tests might take extra 20% development time and later save 20% time spent on debugging/maintenance, while going for another 10% might be twice as time consuming yet yield much lesser gains).

Again, you probably want to ask "Where's the line?" When do you decide "Ok, unit tests for this piece of code are not really needed"? Unfortunately, this kind of judgement comes with experience. Write code, read code, see what others (possibly more experienced developers) do and learn.

If I were to give couple of generic advises (what to unit test), those would be:

  • start with business/domain logic code
  • make sure to test all kind of converters/parsers/calculators (those are fairly easy to test, tend to change often [either due to changing requirements or refactorings] and by their nature are error prone)
  • avoid testing simple one-liner methods, unless that one line is crucial in some way
  • write tests for bugs that you discover (and keep them!)
  • don't follow magic fairy-tales of "good code must have 99.99% test coverage" blindly
  • reading questions on topic at programmers.stackexchange.com can often give you different perspective to approach problems
Community
  • 1
  • 1
k.m
  • 30,794
  • 10
  • 62
  • 86
1

Assuming that you're storing your reminders somewhere, perhaps in the plist. You could write a unit test to generate a Reminder object, store it, retrieve the data, and finally generate a usable Reminder class object.

That way you know several things:

A: Your Reminder generation is working

B: Your method of storing the data is working

C: Going from Data to your Reminder object is working

However, you should not expect to be able to Unit test the actual "functionality" of your app. Such as touch events or navigation controls. These should be left to Acceptance testing which is an entirely different discussion.

SethHB
  • 743
  • 4
  • 12
1

Test all the code you write. And if you want to be really cool, write the test first. If you have a method on a model or controller, you should also have a test for it.

Without knowing more about your code, its hard to advise. But it sounds like you would have a controller (like RemindersController) and a model (like Reminder). This would be a basic outline I would start with:

  • RemindersController

    • should add a new reminder
    • should update an existing reminder
    • should delete an existing reminder
  • Reminder

    • initWithMessage:atTime: should set a message
    • initWithMessage:atTime: should set a time
Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • I would also encourage you to always test everything line of code you write (ideally). Have a look at Graham Lee's book, Test Driven iPhone Development: http://www.amazon.com/Test-Driven-iOS-Development-Developers-Library/dp/0321774183 – Kasper Munck Oct 03 '12 at 20:22
0

I follow these principles in choosing what types of tests to write and when:

  • Focus on writing end-to-end tests. You cover more code per test than with unit tests and so get more testing bang for the buck. Make these the bread-and-butter automated validation of your system as a whole.

  • Drop down to writing unit tests around nuggets of complicated logic. Unit tests are worth their weight in situations where end-to-end tests would be difficult to debug or unwieldy to write for adequate code coverage.

  • Wait until the API you are testing against is stable to write either type of test. You want to avoid having to refactor both your implementation and your tests.

Rob Ashton has a fine article on this topic, which I drew heavily from to articulate the principles above.

Edward Brey
  • 40,302
  • 20
  • 199
  • 253
  • "Wait until the API you are testing against is stable" - this defeats one of the major benefits of TDD, namely that your tests are the first client for your API, which in my experience leads to much better APIs than when you write your tests after the production code. – Frank Schmitt Mar 22 '13 at 13:35
  • @Frank: I agree that you want to enough write code to hone the usability of your API. Maybe it is in the form of unit tests, but maybe it's other implementation code you have to write anyway, or some of each. In any case, the focus should be real-world usage. To minimize rework, write only as much as need be to validate your API design. – Edward Brey Mar 22 '13 at 13:47