繁体   English   中英

如何使用反射对Dispose()进行单元测试?

[英]How to unit test Dispose() using reflection?

我想为实现IDisposable的类编写单元测试。 该类有许多私有字段,也实现IDisposable。 在我的测试中,我想验证当我调用Dispose() ,它正确地在所有IDisposable字段上调用Dispose() 基本上,我希望我的单元测试看起来像这样:

var o = new ObjectUnderTest();
o.Dispose();
Assert.IsFalse(ObjectHasUndisposedDisposables(o));

我正在考虑使用反射来实现这一目标。 看起来这是一个相当普遍的要求,但我找不到它的任何例子。

有人试过吗?

编辑 - 我不想将Disposables注入被测试的类中。

验证您正在寻找的行为而不在代码中进行任何重构的唯一方法是使用代码编织工具Eg; Typemock隔离器,MsFakes等......

以下代码段显示了使用MsFakes验证行为的方法:

[TestMethod]
public void TestMethod1()
{
    var wasCalled = false;
    using (ShimsContext.Create())
    {
        ForMsFakes.Fakes.ShimDependency.AllInstances.Dispose = dependency =>
        {
            wasCalled = true;
        };

        var o = new ObjectUnderTest();

        o.Dispose();
    }

    Assert.IsTrue(wasCalled);
}

public class Dependency : IDisposable
{
    public void Dispose() {}
}

public class ObjectUnderTest: IDisposable
{
    private readonly Dependency _d = new Dependency();

    public void Dispose()
    {
        _d.Dispose();
    }
}

没有通用的方法来处理这个问题。 IDisposeable接口不需要您跟踪是否已调用dispose。

我能想到你能解决的唯一方法就是使用依赖注入注入所有这些一次性类。 如果你这样做,你可以模拟注入的类并跟踪是否调用了dispose。

    [TestMethod]
    public void TestAllDisposeablesAreDisposed()
    {
        var fooMock = new Mock<IFoo>();
        fooMock.Setup(x=>x.Dispose())
            .Verifiable("Dispose never called on Foo");

        var barMock = new Mock<IBar>();
        barMock.Setup(x => x.Dispose())
            .Verifiable("Dispose never called on Bar");

        using (var myClass = new MyClass(fooMock.Object, barMock.Object))
        {
        }

        fooMock.Verify();
        barMock.Verify();
    }

您是否正在尝试测试您的IDisposable行为是否在给定的类中有效,或者您是否想要测试管理您的一次性类的内容是否实际上称为IDisposable 这是有效的,如果你不确定它是否被调用,你想确定。 (我已经为此写了测试。)

为此你可以创建一个这样的简单类:

public class DisposeMe : IDisposable
{
    public bool Disposed {get;set;}
    public void Dispose()
    {
        Disposed = true;
    }
}

然后你可以断言Disposed是真的,当你期望它被处置。

例如,当我从DI容器创建类时,我已经使用了它,并且我想确认当容器创建的类被释放时它的一次性依赖性被释放。 我无法在实际的具体类中跟踪它,但我可以测试DI容器正在执行我认为它应该做的事情。 (这不是我一遍又一遍地写的测试。例如,一旦我确认了Windsor的预期行为,我就不会继续为它编写单元测试。)

如果您不愿意在构造函数中使用依赖项注入,因为这会强制您更改接口,那么您可以通过属性注入依赖项。 如果没有注入任何内容,则为您的属性提供一个默认值,这样当您使用该类时,您不必记住传递真正的实现

例如

public class ObjectUnderTest : IDisposable
{
    private IObjectNeedingDisposal _foo;

    public IObjectNeedingDisposal Foo
    {
        get { return _foo ?? (_foo = new ObjectNeedingDisposal()); }
        set { _foo = value; }
    }

    public void MethodUsingDisposable()
    {
        Foo.DoStuff();
    }

    public void Dispose()
    {
        Foo.Dispose();
    }
}

在您的测试中,您可以创建对象的实例并传入类的模拟版本,但在实际实现中,您可以将其保留为未设置,并且它将默认为您想要的类型的实例

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM