【问题标题】:How to partially mock external object如何部分模拟外部对象
【发布时间】:2015-06-02 23:01:08
【问题描述】:

我有类方法来测试依赖对象(Keys 对象)

APIRouter.m

+ (NSURL*)apiURLWithPath:(NSString*)path {
    MyKeys *keys = [MyKeys new];
    NSString *url = [NSString stringWithFormat:@"%@?api_key=%@", path, [keys APIKey]];
    return [NSURL URLWithString:url];
}

我正在尝试部分模拟此 Keys 对象并返回“MY_API_KEY”值,但测试方法失败并返回真正的 API 密钥(例如 as78d687as6d7das8da)。

APIRouterSpec.m

describe(@"APIRouter", ^{
    it(@"should return url for api", ^{
        Keys *keys = [Keys new];
        id keysPartialMock = OCMPartialMock(keys);
        OCMStub([keysPartialMock APIKey]).andReturn(@"MY_API_KEY");
        NSURL *url = [APIRouter apiURLWithPath:@"http://www.api.com/v1/events"];
        expect([url absoluteString]).to.equal([NSString stringWithFormat:@"http://www.api.com/v1/events?api_key=MY_API_KEY"]);
    });
});

【问题讨论】:

    标签: ios objective-c unit-testing bdd ocmock


    【解决方案1】:

    也许这对你有用:

    您的测试方法之外的某个地方:

    static NSString *gMockApiKey = @"MY_API_KEY";
    

    像这样存根方法:

    OCMStub([keysPartialMock APIKey]).andDo(^(NSInvocation *invocation)
    {
        [invocation setReturnValue:&gMockApiKey];
    });
    

    编辑:

    由于 APIRouter 可能使用它自己的 Keys 实例,您可以尝试模拟类:

    id keysMock = OCMClassMock([Keys class]);
    OCMStub(ClassMethod([keysMock APIKey])).andDo(^(NSInvocation *invocation)
    {
        [invocation setReturnValue:&gMockApiKey];
    });
    

    编辑2:

    所以.. 我认为模拟它的正确方法是创建一个 Keys 的模拟实例。

    测试文件顶部的某处:

    static Keys *gMockedKeys = nil;
    static NSString *gMockApiKey = @"MY_API_KEY";
    

    设置:

    - (void)setUp {
    
        [super setUp];
    
        gMockedKeys = [Keys new];
    
        id keysPartialMock = OCMPartialMock(gMockedKeys);
        OCMStub([keysPartialMock APIKey]).andDo(^(NSInvocation *invocation)
        {
            [invocation setReturnValue:&gMockApiKey];
        });
    }
    

    测试:

    - (void)testAPIURLWithPath {
    
        id keysMock = OCMClassMock([Keys class]);
        OCMStub([keysMock new]).andReturn(gMockedKeys);
    
        NSURL *url = [APIRouter apiURLWithPath:@"http://www.api.com/v1/events"];
        NSString *expectedUrlString = [url absoluteString];
        XCTAssertEqualObjects(expectedUrlString, @"http://www.api.com/v1/events?api_key=MY_API_KEY", @"It Should work now..");
    }
    

    【讨论】:

    • 好吧,我想我知道为什么了。我们正在尝试对 Keys 和 APIRouter 实例进行部分模拟(我假设)正在使用它自己的实例。您可以尝试 Keys 的类模拟。我会编辑答案。
    • 我也试过了,但还是不行 :) APIKeyKeys 类的实例方法。有一个gist 用于更详细的接口等代码。
    • @tailec 我再次更新了我的答案...它现在应该可以工作了,但您可能需要进行一些重构和清理。
    • 它工作,太棒了!谢谢你。我正在学习 OCMock,这个例子看起来很复杂,可以实现简单的事情。
    • @tailec 起初它可能看起来很复杂,但我认为这是要走的路。您可以将此概念用于更复杂的情况。您实际上是在“注入”一个模拟类以供您正在测试的其他类使用。虽然我不确定使用全局变量是否正确,但也许它们可以成为测试类的成员。无论如何,我很高兴它成功了:)
    猜你喜欢
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多