使用 NSURLConnection 进行单元测试

发布于 2024-07-18 09:04:42 字数 1042 浏览 4 评论 0原文

我想测试一段使用网络的代码(具体来说是 NSURLConnection 类)。 代码(让我们称之为 NetworkManager )看起来有点像这样:

- (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 类设计保持干净,并且在测试中不需要太多魔法或太多代码。

I want to test a piece of code that uses network (the NSURLConnection class, to be specific). The code (let’s call it NetworkManager) looks a bit like this:

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

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

In the unit test I would like to get rid of the networking, ie. replace the NSURLConnection object by a mock. How do I do this?

I’ve tried creating a partial mock of the NetworkManager that would replace the buildConnection method by a stub. The problem is that partial mocks as done by OCMock only stub messages from the outside world – sending buildConnection from the startNetworkSync invokes the original method, not the stub.

I have also tried monkey-patching the NetworkManager class through a category. This works, I can easily override the buildConnection method by other code and replace the real NSURLConnection with a stub. The problem is that I found no simple way I could get the stubbed connection in the test – the connection is a private part of the NetworkManager.

Then I could subclass the NetworkManager, override the buildConnection method and add an instance variable plus an accessor for the created connection. This seems like a lot of code, though.

How would you solve this? I am looking for a solution that keeps the NetworkManager class design clean and does not require much magic nor much code in the test.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

红玫瑰 2024-07-25 09:04:42

这就是依赖注入旨在解决的问题; 如果您使用 startNetworkSyncWithConnection:(NSURLConnection*) 代替,您可以使用模拟连接轻松测试该方法。 如果您不想更改客户端的 API,您甚至可以将 startNetworkSync 保留为包装器,除了使用 [self buildConnection] 作为调用该新方法之外什么也不做。争论。

This is the kind of thing dependency injection is designed to solve; if you use startNetworkSyncWithConnection:(NSURLConnection*) instead you can easily test the method with a mock connection. If you don't want to change the API for your clients you could even keep startNetworkSync as a wrapper that does nothing but call that new method with [self buildConnection] as the argument.

冰葑 2024-07-25 09:04:42

我修改了 OCMock 以支持真正的部分模拟,请参阅 GitHub 上的存储库

I modified OCMock to support real partial mocks, see the repo on GitHub.

遥远的绿洲 2024-07-25 09:04:42

我最近使用的另一个解决方案是完全抽象网络接口。 如果该类需要来自网络的一些数据,它可能会与某些可以明确建模为协议的服务器服务进行交互:

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

然后您将拥有一个真正的 HTTP 实现和一个测试实现。 这意味着更多的工作,但也意味着更好的可测试性。 测试不那么脆弱而且更方便,因为测试网络层可以做​​任何你需要的事情。

Another solution I have used recently is to completely abstract the networking interface. If the class needs some data from the network, it probably interacts with some server service that can be explictly modelled as a protocol:

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

And then you’ll have a real HTTP implementation and a testing one. This means more work, but also much better testability. The tests are less brittle and much more convenient, since the testing network layer can do whatever you need.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文