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

Vad*_*dim 17 c# unit-testing idisposable legacy-code

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

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

public bool Foo()
{
    using (IMyDisposableClass client = new MyDisposableClass())
    {
        return client.SomeOtherMethod();
    }
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能测试上面的代码?

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

mci*_*321 20

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

public bool Foo()
{
    using (IMyDisposableClass client = _myDisposableClassFactory.Create())
    {
        return client.SomeOtherMethod();
    }
}
Run Code Online (Sandbox Code Playgroud)


Ric*_*ett 17

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

但是,你在这里有一个依赖.所以TDD方法是使用依赖注入.使用像Unity这样的IoC容器可以更容易.

在"正确"执行TDD时,您的思维过程应在此类场景中运行如下:

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

然后你会写一个(或多个)失败的测试,然后你才会在编写Foo函数体的位置,并确定是否需要使用using块.

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

一旦你确定你需要使用一个using块,你就会想要编写一个失败的测试 - 例如使用像Rhino Mocks这样的东西来设置一个期望,这个期望Dispose将被实现的模拟对象调用IMyDisposableClass.

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

[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());
    }
}
Run Code Online (Sandbox Code Playgroud)

存在Foo函数的类,IMyDisposableClass注入为依赖项:

public class Stuff
{
    private readonly IMyDisposableClass _client;

    public Stuff(IMyDisposableClass client)
    {
        _client = client;
    }

    public bool Foo()
    {
        using (_client)
        {
            return _client.SomeOtherMethod();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和界面 IMyDisposableClass

public interface IMyDisposableClass : IDisposable
{
    bool SomeOtherMethod();
}
Run Code Online (Sandbox Code Playgroud)

  • @Richard,我只注入一个工厂Func(或一个真正的Factory接口),而不是依赖,如果类必须管理依赖的整个生命周期(例如创建并销毁它)或创建多个实例.请参阅AutoFac 2中的"自动生成工厂",了解其工作方式(http://code.google.com/p/autofac/wiki/NewInV2) (2认同)
  • 当有人为同一个“Stuff”实例调用“Foo()”两次时会发生什么? (2认同)

Lar*_*abe 6

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

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

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

  • 阿门.看到人们一直在与错误的工具(正则表达式,LINQ)或错误的方法(DDD)进行斗争,这是令人难以置信的,因为它"热"并且他们只是想"酷".加一. (2认同)