如何在C#中模拟没有接口且没有虚拟方法的类?

Dam*_*ien 3 c# unit-testing

我正在为别人的代码编写单元测试,我不允许修改.

说我有:

class BadClass
{
    public BadClass()
    {
        // the service isn't going to be running during testing
        // it also has no interface
        someFlag = AGloballyStoredService.getSomeFlag();
    }

    public bool someFlag;

}
Run Code Online (Sandbox Code Playgroud)

用于:

class AnotherBadClass
{
    public AnotherBadClass(BadClass badClass)
    {
        someFlag = badClass.someFlag;
    }
    public bool someFlag;
}
Run Code Online (Sandbox Code Playgroud)

说我想要测试:

public void AnotherBadClassConstructorTest()
{
    BadClass badClass = new BadClass();
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClass);
    Assert.IsNotNull(anotherBadClass);
}
Run Code Online (Sandbox Code Playgroud)

我想模拟BadClass,但它没有接口,如果服务没有运行,它在构造函数中失败.

考虑到我无法修改我正在测试的代码,是否有一种直接的方法来使其工作?

如果归结为它,我可以告诉他们,他们必须让我修改现有的代码库或接受该模块的10%以下的覆盖率.

pio*_*est 7

考虑到我无法修改我正在测试的代码,是否有一种直接的方法来使其工作?

不.但是,我看到两个非直截了当的选择:

A)使用Microsoft Fakes通过重写库来提供模拟.您不必修改代码.示例:您可以修改静态DateTime.Now以返回您选择的日期,如下所示:

System.Fakes.ShimDateTime.NowGet = 
() =>
{ return new DateTime(fixedYear, 1, 1); };
Run Code Online (Sandbox Code Playgroud)

B)您可以尝试继承测试的类并覆盖使用的方法/ ctors.但是有两个限制.您必须能够使用模拟对象实例化/交换已测试类的实例(通过使用反射,您可以访问私有成员),并且模拟方法必须是虚拟的.在您的情况下,您将创建:

class BadClassMock : BadClass
{
    public BadClassMock()
    {
    }

    public bool someFlag;

    public void InitForTest()
    {
        someFlag = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

它会工作,只要你不会调用基础构造函数.你可以从这里使用令人讨厌的FormatterServices.GetUninitializedObject()技巧:在C#中使用反射创建没有默认构造函数的类型实例

然后:

public void AnotherBadClassConstructorTest()
{
    BadClassMock badClassMock = (BadClassMock)FormatterServices.GetUninitializedObject(typeof(BadClassMock));
    badClassMock.InitForTest();
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClassMock);
    Assert.IsNotNull(anotherBadClass);
}
Run Code Online (Sandbox Code Playgroud)

是的,这是一个非常大的解决方法.显然,最好的方法是说服作者修改代码.