对检查互联网连接的模块进行单元测试
我有一个 C# 模块,负责获取 Windows Vista 计算机上“连接到互联网”的网络适配器列表。 该模块使用“网络列表管理器 API "(或 NLM API)迭代所有网络连接并返回 IsConnectedToInternet 值为 true 的所有网络连接。
我在此 SO问题
为了测试这个模块,我决定编写一个助手,它根据另一种逻辑返回互联网连接接口的列表,因此这将是对原始版本的一种“现实检查”模块的逻辑。 请注意,对于测试助手,我愿意使用可能被认为是生产代码的不良做法的检测方法(例如,依赖某些可用的互联网资源,如“Google”),以防它关闭、被我们的内部防火墙阻止等。与已部署的产品库相比,修复测试相对容易)。
我选择的替代检测方法是尝试使用 TcpClient 连接到“www.google.com:80”。 我的问题:当我有多个连接的适配器(例如无线和 LAN)时,其中一个适配器的检测方法会失败,并出现错误“在已连接的套接字上发出连接请求”。
我的问题有三个方面:
您通常会如何测试这样的模块? 您是否支持用不同的方式做同样的事情并比较结果的想法,或者这是一种矫枉过正的做法,我应该依赖系统的 API? 我的主要问题是,很难预先配置系统,以便我提前知道预期结果是什么。
您会建议什么替代逻辑? 上述问题中建议的一件事是查看路由表 - 将每个具有目的地为 0.0.0.0 的路由条目的适配器视为“连接到互联网”怎么样? 其他建议?
您知道为什么我在当前测试逻辑中收到“已连接”错误吗?
I have a C# module responsible for acquiring the list of network adapters that are "connected to the internet" on a windows Vista machine. The module uses the "Network List Manager API" (or NLM API) to iterate over all network connections and returns all those for which the IsConnectedToInternet value is true.
I received some suggestions for the implementation of this module in this SO question
To test this module I've decided to write a helper that returns the list of internet connected interfaces based on another logic, so it would be a sort of a "reality check" for the original module's logic. Note that for the test helper I am willing to use detection methods that might be considered bad practice for production code (e.g. relying on some internet resource like "Google" to be available - in case it shuts down, blocked by our internal firewall etc. it's relatively easy to fix the test as opposed to a deployed product base).
The alternative detection method I chose was to try to connect to "www.google.com:80" with a TcpClient. My problem: When I have more than one connected adapter (e.g. both wireless and LAN) the detection method fails for one of them with the error "A connect request was made on an already-connected socket".
My question is three fold:
How would you go about testing such a module in general? Do you support the idea of doing the same thing in a different way and comparing the results or is it an overkill and I should rely on the system's API? My main problem here, is that it's very hard to pre-configure the system so that I'll know what the expected results are in advance.
What alternative logic would you suggest? One thing that was suggested in the aforementioned question was looking at the routing table - what about considering each adapter that has a routing entry with a destination of 0.0.0.0 as "connected to the internet"? Other suggestions?
Do you understand why I get the "already-connected" error with the current test logic?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我只能回答你关于单元测试的问题。
用您自己的话来说,您正在测试的代码是“一个 C# 模块,负责获取 Windows Vista 计算机上‘连接到互联网’的网络适配器列表。该模块使用‘网络列表管理器 API’(或 NLM API)来迭代所有网络连接并返回 IsConnectedToInternet 值为 true 的所有网络连接。”
如果我正在编写这个模块,我将首先使用 NLM API 的接口,将其称为...NLMAPIService。 现在,对于真正的代码,创建一个实现 NLMAPIService 并适应真正的 NLM API 的适配器。
为了进行测试,创建一个实现 NLMAPIService 的 FakeNLMAPI 类,并将其所有数据保存在内存中的某处、XML 文件等中。 您的模块仅调用 NLMAPIService 上的方法,因此您不必根据是否正在测试而更改任何“实际”代码。
因此,在您的测试设置方法中,您可以实例化 FakeNLMAPI 并将其传递给您的模块,并在生产中实例化您的 NLM API 适配器。
我假设您可以实例化和修改表示网络连接的对象。 如果没有,您可以遵循相同的模式来伪造实际的网络连接对象。
I can only answer your question about the unit test.
The code you're testing is, in your own words, "a C# module responsible for acquiring the list of network adapters that are 'connected to the internet' on a windows Vista machine. The module uses the 'Network List Manager API' (or NLM API) to iterate over all network connections and returns all those for which the IsConnectedToInternet value is true."
If I were writing this module, I would first use an interface for the NLM API, call it...NLMAPIService. Now, for the real code, create an Adapter that implements NLMAPIService and adapts the real NLM API.
For testing, create a class FakeNLMAPI that implements NLMAPIService and has all of its data in-memory somewhere, or in an XML file, or whatever. Your module calls methods only on the NLMAPIService, so you don't have to change any "real" code depending on whether you're testing or not.
Therefore, in your test setup method, you can instantiate FakeNLMAPI and pass it to your module, and in production, instantiate your NLM API Adapter.
I'm going to assume that you can instantiate and modify the object that represents a network connection. If not, you can follow the same pattern for faking the actual network connection object.
依赖注入是处理此类问题的一种非常方便的模式。 不是简单地在代码中直接使用 NLM API 组件,而是定义一个接口和一个实现该接口并充当 NLM API 代理的类。 在构造函数中将此类的实例传递给您的模块,并让您的模块使用它。 在单元测试中,不要使用真正的代理对象,而是使用返回已知信息的模拟对象(它甚至不必引用 NLM API)来测试模块的逻辑。 当然,您的代理类也需要一些测试,但其中的逻辑要简单得多——可能只是一些数据封送。 您也许能够说服自己它的正确性,或者如果不正确,请对其进行一些手动测试以确保它正常工作。
Dependency Injection is a very handy pattern to deal with issues like this. Instead of simply using the NLM API components directly in your code define an interface and a class that implements it and serves as a proxy to the NLM API. Pass an instance of this class to your module in the constructor and have your module use it. In your unit tests, instead of the real proxy object, use a mock object that returns known information -- it doesn't even have to reference the NLM API -- to use in testing the logic of your module. Granted, your proxy class will need some testing as well, but the logic in it is much simpler -- probably just some data marshaling. You might be able to convince yourself of its correctness or, if not, do some manual testing on it to make sure that it is working properly.
单元测试不应访问外部资源。 为了对您的方法进行单元测试,我将删除网络列表管理器 API。
您仍然需要验收测试层。 在该测试环境中,您应该复制您希望在您的环境中支持的各种配置,设置您自己的网络主机、路由器、机器配置。 验收测试应使用 Fitnesse 等工具在用户体验级别进行。
UnitTests shouldn't access to external resources. To UnitTest your method, I would stub out the Network List Manager API.
You still need an acceptance test layer. In that test environment you should replicate various configurations you expect to support in your environment, setup your own webhosts, routers, machine config. Acceptance testing should be done at the user experience level using a tool like Fitnesse.