Donnerstag, 19. Februar 2015

How to write a unit test for your iOS app

Here are some general guidelines that I am sticking to when I write a unit test for an iOS app.

Unit tests for your System Under Test (SUT) go into a file called SUT_Tests.m. This file contains a class called SUT_Tests. Replace SUT with the class you are testing; e.g. WebService_Tests.
This class has the following features:
  • Inherits from XCTestCase
  • Has no header file. The class declaration goes into SUT_Tests.m.
  • Declares the SUT's private properties and methods in a category called Testing
  • Has no private methods. Unit tests should share as less code as possible - they need to run in isolation. Having private methods tends to sharing state among unit tests which breaks isolation.
  • Has short methods. Try to stick to a maximum of 15 lines per test* method. If you need more lines, try to break up the method that you are testing or handle cases like testing a method with nil and @"" in separate methods. 
  • Methods have self explanatory names. E.g. testMethodXYWithNil, or testMethodXYWithEmptyString
When writing your tests, keep the FIRST principle in mind.
You can use this as a template:

#import 
#import 
#import "SUT.h"

#pragma mark - private declarations

/*
 * Declare your SUT's private properties and
 * methods in this category.
 */
@interface SUT (Testing)

@property (nonatomic, strong) id aPrivateProperty;

- (BOOL) aPrivateMethod;

@end

#pragma mark -

/*
 * The class declaration goes into the .m file.
 */
@interface SUT_Tests : XCTestCase

@property (nonatomic, strong) SUT *sut;
@property (nonatomic, strong) id   sutMock;

@end

#pragma mark -

@implementation SUT_Tests

- (void)setUp 
{
    [super setUp];
    
    self.sut     = [[SUT alloc] initWithDesignatedInitializer]];
    self.sutMock = OCMPartialMock(self.sut);
}

- (void)tearDown 
{    
    [self.sutMock stopMocking];
    
     self.sutMock = nil;
     self.sut     = nil;
    
    [super tearDown];
}

#pragma mark - tests

/*
 * Your unit tests go here.
 */

- (void)testYourSUT 
{

}