2009-05-03 192 views
3

我想测试一段使用网络的代码(NSURLConnection类,具体而言)。代码(姑且称之为NetworkManager)看起来有点像这样:使用NSURLConnection进行单元测试

- (id) buildConnection 
{ 
    // some more code and then: 
    return [NSURLConnection …]; 
} 

- (void) startNetworkSync 
{ 
    id connection = [self buildConnection]; 
    //… 
} 

在单元测试中,我想摆脱网络,即。用模拟替换NSURLConnection对象。我该怎么做呢?

我试过创建了NetworkManager的部分模拟,它将用存根代替buildConnection方法。问题是部分嘲讽如OCMock所做的仅存根外部世界的消息 - 从startNetworkSync发送buildConnection将调用原始方法,而不是存根。

我也尝试通过类别猴子修补NetworkManager类。这可以工作,我可以轻松地用其他代码覆盖buildConnection方法,并用存根替换实际的NSURLConnection。问题是,我发现没有简单的方法可以在测试中获得桩连接 - 连接是NetworkManager的私有部分。

然后,我可以继承NetworkManager,覆盖buildConnection方法,并为创建的连接添加一个实例变量和一个访问器。不过,这看起来好像很多代码。

你会如何解决这个问题?我正在寻找一种解决方案,以保持NetworkManager类设计的清洁,并且在测试中不需要太多魔法或代码。

回答

3

这是一种依赖注入被设计来解决的事情;如果使用startNetworkSyncWithConnection:(NSURLConnection*),则可以使用模拟连接轻松测试该方法。如果您不想为您的客户更改API,您甚至可以将startNetworkSync作为一个包装器,它只会以[self buildConnection]作为参数来调用该新方法。

+0

好吧,我已经或多或少的这样做了。客户对网络一无所知,他们只发送和接收数据,但我已经添加了向进程注入“外部”连接的方法,这有助于测试。谢谢。 – zoul 2009-05-05 07:09:41

+0

@zoul,请粘贴您的解决方案的代码。谢谢! – ma11hew28 2011-03-16 17:56:43

2

我修改了OCMock以支持真正的部分模拟,请参阅repo on GitHub

0

我最近使用的另一个解决方案是完全抽象网络接口。如果该类从网络上需要一些数据,它可能与可以显式地建模为一个协议的一些服务器服务交互:

@protocol SomeNetworkService 
- (NSArray*) allAvailableFoos; 
- (void) insertNewFoo: (Foo*) foo; 
@end 

然后你就会有一个真正的HTTP实现和测试一个。这意味着更多的工作,但也更好的可测试性。由于测试网络层可以做​​任何您需要的测试,因此测试更简单,更方便。