I am writing unit tests for an iOS application. I clearly understand the benefits of writing unit tests & TDD, but I am confused about what kind of tests you can write for methods like this;

-(void)setCurrentView:(NSString *)view data:(NSString *)data
{
    if (!isEmpty(view)) {
        [Crashlytics setObjectValue:view forKey:kCurrentView];
        if (!isEmpty(data)) {
            [Crashlytics setObjectValue:data forKey:kCurrentViewData];
        }
    }
}

It is written in objective C & Crashlytics is a third part API.

  • We can pass NULL & nil values & test that it doesn't throw any exception
  • Other than this we can test that the values are set properly (isEqual)

Any other test cases we can use here..

Update The above method doesn't work as excepted. Calling class method "setObjectValue" is not sending anything to Crashlytics dashboard. I have to call the the instance method in Crashlytics to make it work..

[[Crashlytics sharedInstance] setObjectValue:view forKey:kCurrentView];
  • 2
    My obj-c is rusty, but if Crashlytics is a static instance, there's probably not much you can do. You could write an instance wrapper for Crashlytics, inject it, and test that it gets invoked correctly, but if you already have working code I probably wouldn't bother for something so simple. – Matthew May 20 '15 at 13:51
up vote 4 down vote accepted

The point of unit testing is testing your code's functionality in isolation. To the extent that your code is simply a wrapper around an external library, it doesn't really have any functionality to unit test.

It may be useful to unit test the NULL and nil values, as you suggest.

However, unit testing the call to the library doesn't seem worthwhile. Suppose you set up a dummy replacement for the Crashlytics object (I don't know objective C, so I don't know exactly how you would do that). What would it prove?

  • That you successfully called the library
  • That you passed in the data received by the method.

These are fairly trivial, and in any case will be more than adequately covered by integration testing.

Despite the other answers to this question, there is in fact a lot of behaviour in this method, and therefore a lot of things that could go wrong if we don't test them. Here are the cases I would check:

  1. When view is not empty and data is not empty, then both view and data are set in the Crashlytics object. This test is sufficient to get statement coverage.
  2. When view is not empty but data is empty, only the view is set in the Crashlytics object.
  3. When view is empty but data is not empty, nothing is set. The cases until here give us branch coverage.
  4. When view is empty and data is empty, nothing is set. The cases until here would give us a kind of parameter coverage.
  5. Setting the view uses the expected key.
  6. Setting the data uses the expected key.

Note that there are different kinds of “empty”, which you should all test. There is a bit of a combinatorial explosion here, so you can either loop over an array of all empty values (preferred) or pick a representative empty value for the primary tests listed above, and then add a few additional tests to check that other empty values work as well, without aiming for full coverage.

Together, these cases form a kind of specification for the method. If you refactor the method or change a related part of the system, these tests will alert you when the specification was violated.

Of course, we don't want to make actual API calls for these tests – after all, we are only testing that our code is correct, not that the API works as expected. It would therefore be wise to use a mock object for these tests, and to use object members rather than global variables (i.e. use some kind of dependency injection).

  • thanks so your suggestion is to mock Crashlytics and perform all kind of tests on it? – Clement Prem May 22 '15 at 7:44
  • @Clement I don't like mocking, but in this case it looks like the method can only be unit-tested meaningfully if you mock the Crashlytics dependency. But that's not the main point of the answer, the important part to take away is that this method does in fact contain a lot of behaviour that should be tested – not just “it doesn't segfault when passed nulls”. – amon May 22 '15 at 16:45

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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