I have found that writing unit tests helps me to discover both the intent and also reusability of code that I'm working on. It has been generally helpful in helping develop my "code smell."
I was working on two unit tests that are basically mirror images, and realized that I was typing code that looked almost identical. I am hoping that someone could help me refactor the similar parts of these two unit tests into shared setup and teardown methods.
- (void)testBlockMethodOne
{
NSError *expectedError = [NSError errorWithDomain:@"An error"
code:42
userInfo:nil];
[mockClassA setError:expectedError];
[mockClassA setRunCompletionBlockImmediately:YES];
__block NSError *actualError = nil;
__block id actualObject = nil;
[classB fireClassAsBlockThenDoThisBlock:^(id object, NSError *error) {
actualObject = object;
actualError = error;
}];
STAssertNil(actualObject, @"There was a problem");
STAssertEqualObjects(actualError, expectedError, @"Got the expected error");
}
- (void)testBlockMethodTwo
{
NSObject *expectedObject = [[NSObject alloc] init];
[mockClassA setObject:expectedObject];
[mockClassA setRunCompletionBlockImmediately:YES];
__block NSError *actualError = nil;
__block id actualObject = nil;
[classB fireClassAsBlockThenDoThisBlock:^(id object, NSError *error) {
actualObject = object;
actualError = error;
}];
STAssertNil(actualError, @"There was a problem");
STAssertEqualObjects(actualObject, expectedObject, @"Got the expected object");
}
A little background about what's being tested: In production code, -fireClassAsBlockThenDoThisBlock is asynchronous. But, of course, in the unit tests I have a mock standing in for "Class A" that just calls the block immediately with either the error or object that I set on the mock.
I've repeated more setup code then I'd really like to between the two tests. My hope is once I see how someone else attacks this, I'll have gained some insight into refactoring block based methods.