如何对机器特定行为进行单元测试?
我正在测试一个静态方法,该方法在检查代理、主机名和各种内容后构建 URL 字符串。 此方法在内部依赖于静态标志 System.Net.Sockets.Socket.OSSupportsIPv6。 因为它是静态的,所以我无法模拟这种依赖关系。
编辑:(这被简化了很多......我无法使用接受 true/false 的标志来修改方法的结构)。
在 XP 开发计算机上,所讨论的方法返回可预测的字符串结果(在本例中为 http://hostname/.. ..)。 我们的构建服务器支持 IPv6,返回完全不同的结果(它给我类似 http://192.168 .0.1:80/....)。 请不要问为什么 - 关键是有两种不同的输出类型,它们根据操作系统的依赖性而变化。
测试需要验证返回的主机名或 IP 地址是否有效。 输出很容易检查。 问题是我只能获得可能的输出之一,具体取决于测试运行在哪台机器上。
在这种情况下编写测试的最佳实践是什么? 我是否在测试中放置一个 if 语句来检查标志,然后查找两个不同的输出? 这对我来说似乎很粗略,因为
测试的行为不同 取决于它的环境 运行
我基本上是在耦合测试 到方法,因为你需要 了解该方法的内部原理 设置两种情况。
我是否设置了两个测试,每个环境一个,如果它们处于错误的环境中,它们就会简单地通过? 我是否编写一些复杂的正则表达式来分离出它得到的结果类型并使用更多的 if/else 逻辑来验证它?
任何建议都会有所帮助!
I am testing a static method that builds a URL string after checking proxies and hostnames and all kinds of things. This method internally relies on the static flag System.Net.Sockets.Socket.OSSupportsIPv6
. Because it's static, I cannot mock this dependency.
EDIT: (This is simplified down a lot... I can't modify the structure of the method with the flag to accept a true/false).
On XP development machines, the method under question returns a predictable string result (in this case, http://hostname/.... ). Our build server, which support IPv6, returns a totally different result (it gives me something like http://192.168.0.1:80/....). Please don't ask why - the point is that there are two different output types that vary on an operating system dependency.
The test needs to validate that the returned hostname or IP address is valid. The outputs are easy to check. The problem is that I can only get one of the possible outputs, depending on which machine the test is run on.
What's the best practice for writing the test in this case? Do I put an if statement in my test which checks the flag and then looks for the two different outputs? This seems sketchy to me because
the test is behaving differently
depending on the environment it's
run inI'm basically coupling the test
to the method, because you need to
know the internals of the method to
set up the two cases.
Do I set up two tests, one for each environment, that simply pass if they're in the wrong environment? Do I write some complex regular expression that can separate out what kind of result it got and use more if/else logic to verify it?
Any suggestions would help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以通过介绍中间人来伪造通话。 例如:
这并不完全令人愉快,但它可以让你做你需要做的事情。
ChrisW 的答案类似,但是使用接口。 通常我会喜欢接口解决方案,但感觉它使生产代码和配置变得更加复杂。 我的解决方案当然不太“纯粹”,但可能更务实。 我让你来判断:)
You could fake the call by introducing an intermediary. For instance:
It's not entirely pleasant, but it lets you do what you need to.
ChrisW's answer is similar, but using an interface. Normally I'd be a fan of the interface solution, but it feels like it's making the production code and configuration more complicated. My solution is certainly less "pure" but possibly more pragmatic. I'll let you judge :)
可以将静态方法隐藏在抽象接口后面吗?
Can you hide the static method behind an abstract interface?
您可以考虑将所有可能更改的环境设置包装在实现接口的单独类中。 然后可以将其传递给您编写的静态方法,然后该方法会在需要各种设置时回调接口。
这将允许您在测试时模拟环境设置以进行标准化,以防止出现您所看到的问题。 它还可以让您改变设置来测试不同的条件。
例如
然后你的静态方法就变成了。
然后提供 IEnvironment 的实现,该实现调用静态 System.Net 方法来获取实际使用的设置,但提供一个模拟实现,用于使用已知值进行测试。
如果您不想将接口传递给静态方法,您可以考虑使用单例模式实现一个对象,然后调用该接口。 然后,您可以使用单例的静态方法来访问当前接口的任何内容,尽管这个方法有点混乱,所以我可能会选择前者。
例如,
然后使用静态方法调用它。
您可以在测试中通过更改它,
尽管您需要注意是否正在使用这样的单例进行任何多线程处理。
You could look at wrapping all of the environmental settings that could change in a separate class that implements an interface. This could then be passed to the static method you have written which would then call back against the interface when it needs the various settings.
This would allow you to mock the environmental settings to standardize when testing to prevent the issue you are seeing. It would also let you vary the settings to test different conditions.
e.g.
And then your static method becomes.
Then provide an implementation of IEnvironment that calls against the static System.Net method to get the actual setting for use, but a mock implementation for testing with a known value.
If you don't want to pass the interface into the static method you could possibly look at implementing an object using the singleton pattern that then calls into this interface. The static method you have could then use the singleton to access whatever the current interface is although this method is a little messy so I'd probably go with the former.
E.g.
Then call into it from your static method using.
And you could change it in your tests via
Although you'd need to watch out if you are doing any multithreading with a singleton like that.
我不明白为什么你不能嘲笑这个。 您的方法应该采用
bool SupportsIPv6
参数,并且在实际代码中,您传递它System.Net.Sockets.Socket.OSSupportsIPv6
。 然后,您使用参数 true 和 false 来测试您的方法,并确保它针对 true 和 false 情况输出正确的格式。 瞧,完成了。I don't understand why you can't mock this. Your method should take a
bool SupportsIPv6
parameter, and in the real code, you pass itSystem.Net.Sockets.Socket.OSSupportsIPv6
. Then you test your method with your parameter being both true and false, and make sure it spits out the right formats for both true and false cases. Voila, done.有时确实会发生很难进行有用的单元测试的情况。 我不确定这是否是其中之一,但值得记住。
也就是说,现在定义“有效”是什么意思? 您当然可以测试它的格式是否良好: [0-9]{1,3} 是正则表达式的开始。
您可以使用 ICMP 回显数据包(或 ping(8))测试它是否可达。
如果您可以定义“有效”对您意味着什么,那么就应该定义单元测试。
It does happen sometimes that it's too hard to make a useful unit test. I'm not confident this is one of those cases, but it's worth remembering.
That said, now, define what "valid" means? You can certainly test of it's well-formed: [0-9]{1,3} is a start on a regex for that.
You can test that it's reachable with an ICMP echo packet (or a ping(8)).
If you can define what "valid" means to you, that should defione a unit test.