如何使用`using`语句对方法进行单元测试?

时间:2009-12-23 16:03:16

标签: c# unit-testing idisposable legacy-code

如何为具有using语句的方法编写单元测试?

例如,假设我有一个方法Foo

public bool Foo()
{
    using (IMyDisposableClass client = new MyDisposableClass())
    {
        return client.SomeOtherMethod();
    }
}

我如何测试类似上面代码的内容?

有时我选择不手动使用using语句和Dispose()对象。我希望有人会告诉我一个我可以使用的技巧。

7 个答案:

答案 0 :(得分:17)

如果使用工厂构建IMyDisposableClass(注入父类)而不是使用new关键字,则可以模拟IMyDisposable并对dispose方法调用进行验证。

public bool Foo()
{
    using (IMyDisposableClass client = _myDisposableClassFactory.Create())
    {
        return client.SomeOtherMethod();
    }
}

答案 1 :(得分:16)

如果您已经拥有自己的代码并且正在询问如何测试它,那么您就不会首先编写测试...所以不是真的在做TDD。

但是,你在这里有一个依赖。所以TDD方法是使用Dependency Injection。使用IoCUnity容器可以更轻松地实现这一点。

在“正确”进行TDD时,您的思维过程应该在这种情况下运行如下:

  • 我需要做Foo
  • 为此,我将依赖一个外部依赖,它将实现IMyDisposableClass
  • 的接口(新的或预先存在的)
  • 因此,我将IMyDisposableClass注入通过其构造函数声明Foo的类

然后你会编写一个(或多个)失败的测试,然后你才会在编写Foo函数体的位置,并确定是否需要使用{{1}阻止。

实际上你可能知道是的,你将使用using块。但TDD的一部分原因是,在您(通过测试)证明需要使用需要此对象的对象之前,您无需担心这一点。

一旦确定需要使用using块,您就会想要编写失败的测试 - 例如使用类似Rhino Mocks的内容来设置using的期望将在实现Dispose的模拟对象上调用。

例如(使用Rhino Mocks来模拟IMyDisposableClass)。

IMyDisposableClass

存在Foo函数的类,[TestFixture] public class When_calling_Foo { [Test] public void Should_call_Dispose() { IMyDisposableClass disposable = MockRepository .GenerateMock<IMyDisposableClass>(); Stuff stuff = new Stuff(disposable); stuff.Foo(); disposable.AssertWasCalled(x => x.Dispose()); } } 作为依赖项注入:

IMyDisposableClass

界面public class Stuff { private readonly IMyDisposableClass _client; public Stuff(IMyDisposableClass client) { _client = client; } public bool Foo() { using (_client) { return _client.SomeOtherMethod(); } } }

IMyDisposableClass

答案 2 :(得分:6)

你的问题没有意义。如果您使用的是TDD,那么您应该已经对所编写的内容进行了测试。要求,然后测试,然后设计,然后开发。您的代码要么通过测试,要么不通过。

现在,如果您的问题是如何对上面的代码进行单元测试,那么这完全是另一个问题,我认为其他海报已经在那里回答了问题。

有时我认为有比开发者更多的流行语:)

答案 3 :(得分:2)

这样的包装器方法不是单元可测试的,因为您无法指定相关的前置条件或后置条件。

要使方法可测试,您必须将IMyDisposableClass实例传递给方法或托管Foo的类(并使主机类本身实现IDisposable),因此,您可以使用测试双重而不是真实的东西来验证与它的任何交互。

答案 4 :(得分:0)

你的问题没有意义。如果您正在进行TDD,那么您发布的方法已经已经进行了全面测试,否则它首先就不存在了。所以,你的问题没有意义。

另一方面,如果您发布的方法已经存在,但尚未经过全面测试,那么您无论如何都没有进行TDD,而且您对TDD的问题也没有意义。

在TDD中,对于未经测试的代码存在只是不可能。周期。

答案 5 :(得分:-1)

如果您正在测试Foo,那么您应该查看Foo的输出,而不必担心它在内部使用的类的处理。

如果您想测试MyDisposableClass'dispose方法以查看它是否有效,那么这应该是针对MyDisposableClass构建的单独的单元测试。

您不需要对using { }块进行单元测试,因为这是该语言的一部分。您要么相信它正在工作,要么不使用C#。 :)我没有看到需要编写单元测试来验证是否正在调用Dispose()

答案 6 :(得分:-1)

如果没有Foo规范,我们怎么说如何测试呢?

  1. 获取Foo的规范。
  2. 编写测试以确保它符合所有规范和要求(或合理的子集 - 某些功能可能需要几乎无限量的数据来测试)。
  3. 我相信你在那里有第二个隐含的问题 - 这是如何正确地测试你的MyDisposableClass的使用通过退出using子句释放它时释放对象。这是一个单独的测试问题,不应与Foo的测试结合使用,因为Foo的规范不应该引用特定于实现的细节,例如使用MyDisposabeClass。

    我认为其他海报已经回答了这个问题,所以我不会进一步阐述。