Here are some general guidelines that I am sticking to when I write a unit test for an iOS app.
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 withnil
and@""
in separate methods. - Methods have self explanatory names. E.g.
testMethodXYWithNil
, ortestMethodXYWithEmptyString
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
{
}