我开始使用objective-c进行单元测试,我需要知道如何使用OCMockito和Xcode 6测试块。
我正在测试一个交互程序,这个交互程序应该返回一个数组作为块参数,我必须向Provider文件询问元素。
这是我想要测试的方法:
- (void)userPoiListsWithSuccessBlock:(MNBSavePoisInteractorSuccess)success {
self.poiListEntityArray = [self.poiListProvider poiListsForUser:self.loggedUser];
self.poiListViewObjectArray = [self viewPoiListObjectListWithPoiLists:self.poiListEntityArray];
success(self.poiListViewObjectArray);
}
首先,我设置了要使用的元素
self.mockPoiListProvider = mock([PoiListProvider class]);
self.sut = [[MNBSavePoisInteractor alloc] initWithManagedObjectContext:self.coreDataStack.managedObjectContext andPoiListProvider:self.mockPoiListProvider];
- (UserEntity *)loggedUserMock {
UserEntity *mockLoggedUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([UserEntity class]) inManagedObjectContext:self.coreDataStack.managedObjectContext];
mockLoggedUser.userId=@"1";
mockLoggedUser.username=@"user";
mockLoggedUser.loggedUser=@YES;
return mockLoggedUser;
}
- (InMemoryCoreDataStack *)coreDataStack{
if (!_coreDataStack) {
_coreDataStack = [[InMemoryCoreDataStack alloc] init];
}
return _coreDataStack;
}
- (PoiListEntity *)poiListFake {
PoiListEntity *fake = [NSEntityDescription insertNewObjectForEntityForName:@"PoiListEntity" inManagedObjectContext:self.coreDataStack.managedObjectContext];
fake.name = @"Test";
fake.poisCount = @2;
[fake addContributorsObject:[self loggedUserMock]];
return fake;
}
然后,我做测试。我使用Xcode 6 waitForExpectation
来管理异步方法。我想我做错了什么。
- (void)waitForExpectation {
[self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
if (error) {
NSLog(@"Timeout Error: %@", error);
}
}];
}
- (void)testShouldReturnPoiLists {
XCTestExpectation *expectation = [self expectationWithDescription:@"Waiting method ends"];
[given([self.mockPoiListProvider poiListsForUser:[self loggedUserMock]]) willReturn:@[[self poiListFake]]];
[self.sut userPoiListsWithSuccessBlock:^(NSArray *results) {
[expectation fulfill];
XCTAssert(resutls.count == 1, @"Results %zd", resutls.count);
}];
[self waitForExpectation];
}
我知道,如果我在给定方法中的willReturn中给定对象,当我调用我想要测试的sut方法时,它应该返回我之前给出的内容。这是真的吗?感谢
我没有看到异步代码。您只需要一个捕获结果的块,所以使用__block
变量使结果在块之外可用。然后你可以断言你想要的任何东西:
- (void)testShouldReturnPoiLists {
[given([self.mockPoiListProvider poiListsForUser:[self loggedUserMock]]) willReturn:@[[self poiListFake]]];
__block NSArray *capturedResults;
[self.sut userPoiListsWithSuccessBlock:^(NSArray *results) {
capturedResults = results;
}];
assertThat(capturedResults, hasLengthOf(1));
}
1的长度和赝品之间的关系很难说。让我们也参数化伪造代码:
- (PoiListEntity *)poiListFakeWithName:(NSString *)name count:(NSNumber *)count {
PoiListEntity *fake = [NSEntityDescription insertNewObjectForEntityForName:@"PoiListEntity" inManagedObjectContext:self.coreDataStack.managedObjectContext];
fake.name = name;
fake.poisCount = count;
[fake addContributorsObject:[self loggedUserMock]];
return fake;
}
有了它,我们可以编写更有趣的测试。
我想补充一点,"倾听测试"很重要。围绕核心数据有很多复杂的设置。这告诉我,如果你能重写一些独立于核心数据的东西——完全不知道它——一切都会简单得多。