如何使用“using”语句对方法进行单元测试?
如何为具有 using 语句的方法编写单元测试?
例如,假设我有一个方法 Foo
。
public bool Foo()
{
using (IMyDisposableClass client = new MyDisposableClass())
{
return client.SomeOtherMethod();
}
}
我如何测试类似上面的代码?
有时我选择不手动使用 using
语句和 Dispose()
对象。我希望有人能告诉我一个我可以使用的技巧。
How can I write a unit test for a method that has a using statement?
For example let assume that I have a method Foo
.
public bool Foo()
{
using (IMyDisposableClass client = new MyDisposableClass())
{
return client.SomeOtherMethod();
}
}
How can I test something like the code above?
Sometimes I choose not to use using
statement and Dispose()
an object manually. I hope that someone will show me a trick I can use.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
如果您使用工厂(注入到父类中)而不是使用 new 关键字构造
IMyDisposableClass
,则可以模拟IMyDisposable
并对 dispose 方法调用进行验证。If you construct the
IMyDisposableClass
using a factory (injected into the parent class) rather than using the new keyword, you can mock theIMyDisposable
and do a verify on the dispose method call.如果您已经有了代码并询问如何测试它,那么您就没有先编写测试......所以并没有真正进行 TDD。
但是,您这里拥有的是依赖项。因此,TDD 方法是使用依赖注入。使用 IoC 容器(例如 Unity。
当“正确”执行 TDD 时,您的思维过程应该在这种情况下按如下方式运行:
Foo
Foo
的类中注入一个IMyDisposableClass
您将编写一个 (或更多)测试失败,然后您才会到达编写
Foo
函数体的位置,并确定是否需要使用using
块。实际上,您可能很清楚,是的,您将使用
using
块。但 TDD 的部分要点是,在您(通过测试)证明您确实需要使用需要此功能的对象之前,您无需担心这一点。一旦您确定需要使用
using
块,您就会想要编写一个失败的测试 - 例如使用类似 Rhino Mocks 设置期望,在实现IMyDisposableClassDispose
代码>.例如(使用 Rhino Mocks 来模拟
IMyDisposableClass
)。Foo 函数所在的类,其中
IMyDisposableClass
作为依赖项注入:以及接口
IMyDisposableClass
If you already have your code and are asking how to test it, then you're not writing your tests first...so aren't really doing TDD.
However, what you have here is a dependency. So the TDD approach would be to use Dependency Injection. This can be made easier using an IoC container like Unity.
When doing TDD "properly", your thought processes should run as follows in this sort of scenario:
Foo
IMyDisposableClass
IMyDisposableClass
into the class in whichFoo
is declared via its constructorThen you would write one (or more) tests that fail, and only then would you be at the point where you were writing the
Foo
function body, and determine whether you needed to use ausing
block.In reality you might well know that yes, you will use a
using
block. But part of the point of TDD is that you don't need to worry about that until you've proven (via tests) that you do need to use an object that requires this.Once you've determined that you need to use a
using
block you would then want to write a test that fails - for example using something like Rhino Mocks to set an expectation thatDispose
will get called on a mock object that implementsIMyDisposableClass
.For example (using Rhino Mocks to mock
IMyDisposableClass
).Class in which your Foo function exists, with
IMyDisposableClass
injected as a dependency:And the interface
IMyDisposableClass
你的问题没有意义。如果您正在使用 TDD,那么您应该已经对所编写的内容进行了测试。需求,然后测试,然后设计,然后开发。您的代码要么通过测试,要么没有通过。
现在,如果您的问题是如何对上述代码进行单元测试,那么这完全是另一个问题,我认为其他发帖者已经在那里回答了。
有时我认为流行语比开发者还多:)
Your question doesn't make sense. If you are using TDD, then you should already have a test for what you have written. Requirements, then tests, then design, then development. Either your code passes your tests, or it doesn't.
Now, if your question is how to unit test the above piece of code, then that's another question completely, and I think the other posters have answered it up there.
Sometimes I think there are more buzzwords than developers :)
此类包装方法不可进行单元测试,因为您无法指定相关的前置条件或后置条件。
要使该方法可测试,您必须将
IMyDisposableClass
实例传递到该方法或托管Foo
的类中(并使宿主类本身实现IDisposable
),因此您可以使用测试替身而不是真实的东西来验证与它的任何交互。Wrapper methods like that aren't unit-testable, because you can't specify the relevant preconditions or post-conditions.
To make the method testable, you'll have to pass an
IMyDisposableClass
instance into the method or into the class hostingFoo
(and make the host class itself implementIDisposable
), so you can use a test double instead of the real thing to verify any interactions with it.你的问题没有意义。如果您正在进行 TDD,那么您发布的方法已经经过充分测试,否则它根本就不存在。所以,你的问题没有意义。
另一方面,如果您发布的方法确实已经存在,但尚未经过充分测试,那么您无论如何都没有进行 TDD,并且您关于 TDD 的问题也没有意义。
在 TDD 中,未经测试的代码不可能存在。时期。
Your question doesn't make sense. If you are doing TDD, then the method that you posted is already fully tested, otherwise it couldn't even exist in the first place. So, your question doesn't make sense.
If, on the other hand, the method that you posted does already exist, but isn't fully tested, then you aren't doing TDD anyway, and your question about TDD doesn't make sense, either.
In TDD, it is simply impossible for untested code to exist. Period.
您还可以更改方法签名以允许传递模拟以进行单元测试。这将提供使用工厂的替代方案,工厂也需要进行单元测试。在这里,直接调用方法而不是类构造函数可能更可取。
You could also change the method signature to allow passing in a mock for unit testing. This would provide an alternative to using a factory, which would also need to be unit tested. DI into the method as opposed to the class constructor may be preferable here.
如果您正在测试 Foo,那么您应该查看 Foo 的输出,而不是担心它内部使用的类的处置。
如果您想测试
MyDisposableClass
' dispose 方法以查看它是否正常工作,那么这应该是针对MyDisposableClass
构建的单独单元测试。您不需要对
using { }
块进行单元测试,因为它是该语言的一部分。您要么相信它能正常工作,要么不使用 C#。 :) 我认为不需要编写单元测试来验证是否正在调用Dispose()
。If you are testing Foo, then you should be looking at the output of Foo, not worrying about the disposal of the class it is using internally.
If you want to test
MyDisposableClass
' dispose method to see if it is working, that should be a separate unit test built againstMyDisposableClass
.You don't need to unit test the
using { }
block, since that is part of the language. You either trust that it's working, or don't use C#. :) I don't see the need to write a unit test to verify thatDispose()
is being called.如果没有 Foo 的规范,我们怎么能说如何测试它呢?
我相信您还有第二个隐含的问题 - 即如何正确测试 MyDisposableClass 的使用,当通过退出 using 子句释放对象时如何处置该对象。这是一个单独的测试问题,不应与 Foo 的测试结合起来,因为 Foo 的规范不应引用特定于实现的细节,例如 MyDisposabeClass 的使用。
这个问题我想其他博主已经回答过了,我就不再赘述了。
Without a specification for Foo, how can we say how to test it?
I believe you have a second, implicit question in there - which is how to test that use of your MyDisposableClass correctly Disposes of the object when it is freed by exiting an using clause. This is a separate test issue, and shouldn't be combined with the test of Foo, since the specification of Foo shouldn't reference implementation specific details such as the use of your MyDisposabeClass.
I think the other posters have answered this question, so I won't further elaborate.