如何验证部分mock有一个使用ocmock使用args调用的基本方法?

时间:2012-03-20 11:32:32

标签: objective-c ios ocunit ocmock

我正在使用一个非常简单的Web服务,它使用基类来重用一些常用的功能。测试中的主要方法只是构建一个url,然后使用带有此参数的super / base方法。

- (void)getPlacesForLocation:(Location *)location WithKeyword:(NSString *)keyword
{
    NSString *gps = [NSString stringWithFormat:@"?location=%@,%@", location.lat, location.lng];
    NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@%@", self.baseurl, gps]];
    [super makeGetRequestWithURL:url];
}

这是基本方法定义

@implementation WebService
@synthesize responseData = _responseData;

- (id)init
{
    if (self == [super init])
    {
        self.responseData = [NSMutableData new];        
    }

    return self;
}

- (void)makeGetRequestWithURL:(NSURL *)url
{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
    request.HTTPMethod = @"GET";

    [[NSURLConnection alloc] initWithRequest:request delegate:self];
}

在我的测试中,我创建了一个局部模拟,因为我仍然想调用我的测试对象,但我需要能够验证以特定方式调用super方法。

- (void)testGetRequestMadeWithUrl
{
    self.sut = [[SomeWebService alloc] init];
    Location *location = [[Location alloc] initWithLatitude:@"-33.8670522" AndLongitude:@"151.1957362"];
    NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@%@", self.sut.baseurl, @"?location=-33.8670522,151.1957362"]];
    id mockWebService = [OCMockObject partialMockForObject: self.sut];
    [[mockWebService expect] makeGetRequestWithURL:url];
    [self.sut getPlacesForLocation:location WithKeyword:@"foo"];
    [mockWebService verify];
}

然而,当我运行此测试时,我失败并出现以下错误:

未调用预期方法:makeGetRequestWithURL:https:// ...

我可以告诉这个方法没有被模拟,因为如果我将NSLog放入基本方法,它会在我运行ocunit测试时显示出来(显然它正在运行,只是没有像我想的那样嘲笑它)。

如何修改我的测试/重构我的实现代码以获取我正在寻找的断言?

1 个答案:

答案 0 :(得分:3)

这是一个有趣的案例。我的假设是,如果你用“自我”代替“超级”,那么一切都会按预期工作,即

- (void)getPlacesForLocation:(Location *)location WithKeyword:(NSString *)keyword
{
    NSString *gps = [NSString stringWithFormat:@"?location=%@,%@", location.lat, location.lng];
    NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%@%@", self.baseurl, gps]];
    [self makeGetRequestWithURL:url];
}

问题是部分模拟是通过动态创建子类来实现的。当使用“super”时,方法的查找从父类(您的情况下的基类)开始,这意味着运行时永远不会看到由部分模拟创建的子类中实现的方法。

您的问题的另一个答案是更改设计。而不是使用类层次结构使用两个类。一个类负责创建URL,另一个类负责发出请求。那么你就不需要部分模拟,因为你可以简单地替换请求者。参见单一责任原则[1]和基于继承的组合[2]。

[1] http://en.wikipedia.org/wiki/Single_responsibility_principle

[2] http://en.wikipedia.org/wiki/Composition_over_inheritance