2

我不确定这是否是最好的标题,但基本上我知道一个变量会在运行一个函数时被实例化。我想对该变量进行部分模拟,并期望在实例化变量之前调用某些方法。这是我正在尝试做的一个例子。

-(void)testMethod {
    id mockVar = [OCMock partialMockForObject:self.controller.variable];
    [[mockVar expect] someMethod];

    [self.controller method];
    [mockVar verify];
}

控制器内部的方法看起来像:

-(void)method {
    self.variable = [[Class alloc]init];
    [self.variable someMethod];
}

我收到类似“doesNotRecognizeSelector”的消息。这可能吗?

4

2 回答 2

1

这感觉像是一个奇怪的测试,但如果你模拟访问器,它是可能的:

-(void)testMethod {
    id mockVar = [OCMock mockForClass:[Class class]];
    id mockController = [OCMock partialMockForObject:controller];
    [[[mockController stub] andReturn:mockVar] variable];
    [[mockVar expect] someMethod];

    [self.controller method];
    [mockVar verify];
}

如果你提供一个更具体的例子来说明你想要达到的目标,我可以给你一个更好的答案。

于 2013-10-10T17:48:27.317 回答
1

如果存根属性访问器是可能的,我会同意的。但是,如果您需要部分模拟由真实代码实际创建的实例,则可以将其存储在属性上——setter 方法变成了钩子——但这绝对是丑陋的。

基本思想是使用 OCMArg 的 checkWithBlock: 功能来拦截 set 方法的参数,并在该点创建部分模拟。您可以将其分配给块外的变量以供稍后验证。它看起来像这样:

-(void)testMethod
{
    id mockController = [OCMockObject partialMockForObject:self.controller];
    __block id mockVar;

    [[[mockController stub] andForwardToRealObject] setVariable:[OCMArg checkWithBlock:^BOOL(id param) {
        mockVar = [OCMockObject partialMockForObject:param];
        [[mockVar expect] someMethod];
        return YES;
    }]];

    [self.controller method];  // mockVar will be created and assigned during this call
    [mockVar verify];
}

如果您的真实代码创建了一个对象,并且只将其临时存储在一个局部变量(不是实例变量)中,那么您实际上无能为力,除了重组您的真实代码以使其更易于测试(例如移动代码将对象创建到一个新方法中,这使得存根更容易)。

于 2013-10-12T23:30:35.137 回答