OCMock - "调用的意外方法",尽管已存根



测试代码:

id dataControllerMock = [OCMockObject mockForClass:[RAMImsakyaDataController class]];
[[[dataControllerMock expect] andReturn:dataControllerMock] alloc];
(void)[[[dataControllerMock expect] andReturn:dataControllerMock] init];
[[[dataControllerMock stub] andReturn:@"30.06 , 50.67"] getLocationTitle];
[self.viewController viewDidLoad];
XCTAssertTrue([self.viewController.title isEqualToString:@"30.06 , 50.67"], @"View controller title is wrong");
[dataControllerMock verify];

问题是,dataControllerMock导致失败与"意外的方法调用:getLocationTitle"!我确实存根了这个方法。即使我把存根改成期望值,也是一样的。当我在viewDidLoad内部断点时,模拟已经如预期的那样存在,但它不识别getLocationTitle方法。

更新:这里是viewDidLoad代码
NSString *location = [self.dataController getLocationTitle];
if (location == nil) {
    self.title = @"إمساكية رمضان ١٤٣٥ هـ";
} else {
    self.title = [NSString stringWithFormat:@"إمساكية رمضان ١٤٣٥ هـ (توقيت %@)", location];
}

为什么不采用不同的方法并使用部分模拟呢?

RAMImsakyaDataController* realObject = [RAMImsakyaDataController new];
id partialObject = [OCMockObject partialMockForObject:realObject];
[[[partialObject stub] andReturn:@"30.06 , 50.67"] getLocationTitle];
[partialObject viewDidLoad]; // Method under test
XCTAssertTrue([partialObject.title isEqualToString:@"30.06 , 50.67"], @"View controller title is wrong");

我发现尝试模拟alloc会导致困难的行为。

编辑

// In MyViewController
- (RAMImsakyaDataController*)dataController {
    if (!_dataController) {
        _dataController = [[RAMImsakyaDataController alloc] init];
    }
    return _dataController;
}
Then partial mock the VC and replace this method with one that returns your partially mocked data controller.

我的猜测是OCMock未能正确模拟数据控制器的+alloc方法,所以你的视图控制器使用真正的数据控制器而不是模拟。

我有一个困难的时间模拟对象创建。我最终所做的不是试图模拟+alloc,而是将可测试性存根放在我想要测试的对象上,这些对象创建了它们的依赖关系,然后我可以使用被测试对象的部分模拟来覆盖对象创建。如:

@implementation ViewController
  - (void)init {
    ...
    _dataController = [self newDataController];
    ...
  }
  - (DataController *)newDataController {
    return [[DataController alloc] init];
  }
@end

然后在我的test

ViewController *underTest = [ViewController alloc];
id mockUnderTest = [OCMockObject partialMockForObject:underTest];
id mockDataController = [OCMockObject niceMockForClass:[DataController class]];
[[[mockUnderTest stub] andReturn:[mockDataController retain]] newDataController];
underTest = [underTest init];

最新更新