使用 Xcode 6 和 OCMockito 测试块
Testing blocks with Xcode 6 and OCMockito
我开始使用 objective-c 进行单元测试,我需要知道如何使用 OCMockito 和 Xcode 6 测试块。
我正在测试一个交互器,这个交互器应该return一个数组作为块参数,我必须向提供者文件询问元素。
这是我要测试的方法:
- (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 方法时它应该 return 我之前给出的。真的吗?
谢谢
我没有看到异步代码。您只需要一个捕获结果的块,因此使用 __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;
}
有了它,我们可以编写更有趣的测试。
我确实想补充一点,"listen to the tests." 围绕 Core Data 有很多令人费解的设置很重要。这告诉我,如果你可以重写一些独立于 Core Data 的东西——完全不了解它——一切都会简单得多。
我开始使用 objective-c 进行单元测试,我需要知道如何使用 OCMockito 和 Xcode 6 测试块。
我正在测试一个交互器,这个交互器应该return一个数组作为块参数,我必须向提供者文件询问元素。
这是我要测试的方法:
- (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 方法时它应该 return 我之前给出的。真的吗? 谢谢
我没有看到异步代码。您只需要一个捕获结果的块,因此使用 __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;
}
有了它,我们可以编写更有趣的测试。
我确实想补充一点,"listen to the tests." 围绕 Core Data 有很多令人费解的设置很重要。这告诉我,如果你可以重写一些独立于 Core Data 的东西——完全不了解它——一切都会简单得多。