代码之家  ›  专栏  ›  技术社区  ›  Vadim

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

  •  12
  • Vadim  · 技术社区  · 15 年前

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

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

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

    如何测试上面的代码之类的东西?

    有时我选择不使用 using 语句和 Dispose() 手动对象。我希望有人能给我看一个我能用的技巧。

    7 回复  |  直到 6 年前
        1
  •  17
  •   mcintyre321    6 年前

    如果你建造 IMyDisposableClass 使用工厂(注入到父类中)而不是使用新关键字,可以模拟 IMyDisposable 并对Dispose方法调用进行验证。

    public bool Foo()
    {
        using (IMyDisposableClass client = _myDisposableClassFactory.Create())
        {
            return client.SomeOtherMethod();
        }
    }
    
        2
  •  16
  •   SteveC    11 年前

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

    但是,您在这里拥有的是依赖关系。所以TDD的方法是 Dependency Injection . 使用 IoC 类容器 Unity .

    当正确地执行TDD时,在这种情况下,您的思维过程应该如下运行:

    • 我需要做一个 Foo
    • 为此,我将依赖一个外部依赖项来实现 IMyDisposableClass
    • 因此我会注射 IMY可分解类 在课堂上 通过其构造函数声明

    然后,您将编写一个(或多个)失败的测试,只有这样,您才能在编写 函数体,并确定是否需要使用 using 块。

    实际上,你很可能知道,是的,你将使用 使用 块。但是,TDD的一个要点是,在您(通过测试)证明您确实需要使用一个需要这个的对象之前,您不需要担心这个问题。

    一旦确定需要使用 使用 块,然后希望编写一个失败的测试-例如使用 Rhino Mocks 设定一个期望 Dispose 将在实现的模拟对象上调用 IMY可分解类 .

    例如(使用犀牛模型来模拟 IMY可分解类 )

    [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());
        }
    }
    

    类中存在foo函数,使用 IMY可分解类 作为依赖注入:

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

    以及界面 IMY可分解类

    public interface IMyDisposableClass : IDisposable
    {
        bool SomeOtherMethod();
    }
    
        3
  •  6
  •   Larry Watanabe    15 年前

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

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

    有时我觉得有比开发人员更多的流行词:)

        4
  •  2
  •   Jeff Sternal    15 年前

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

    要使方法可测试,必须通过 IMyDisposableClass 方法或类宿主中的实例 Foo (并使宿主类本身实现 IDisposable ,所以您可以使用一个测试双精度而不是真实的东西来验证与它的任何交互。

        5
  •  0
  •   Jörg W Mittag    15 年前

    你的问题没有道理。如果您正在进行TDD,那么您发布的方法是 已经 完全测试过,否则它根本就不存在。所以,你的问题没有意义。

    另一方面,如果你发布的方法已经存在,但是还没有完全测试过,那么不管怎样,你也没有做TDD,你关于TDD的问题也没有意义。

    在TDD中,它只是 不可能的 存在未测试的代码。期间。

        6
  •  -1
  •   womp    15 年前

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

    如果你想测试 MyDisposableClass 'Dispose方法以查看它是否工作,它应该是针对 我的可处置类 .

    你不需要单元测试 using { } 块,因为这是语言的一部分。你要么相信它在工作,要么不使用c。:)我不认为需要编写单元测试来验证 Dispose() 正在被呼叫。

        7
  •  -1
  •   Larry Watanabe    15 年前

    如果没有foo的规范,我们怎么能说如何测试它呢?

    1. 获取foo的规范。
    2. 编写测试以确保它满足所有规范和要求(或合理的子集——有些函数可能需要无限量的数据进行测试)。

    我相信你还有一个隐含的问题,那就是如何测试当通过退出using子句释放对象时,MyDisposable类的使用是否正确地释放了对象。这是一个单独的测试问题,不应与foo的测试结合使用,因为foo的规范不应引用实现特定的细节,例如myDisposabeClass的使用。

    我想其他海报已经回答了这个问题,所以我不会再详细说明。

    推荐文章