如何模拟c#中没有接口和虚方法的类

本文关键字:接口 方法 何模拟 模拟 | 更新日期: 2023-09-27 18:06:01

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

假设我有:

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;
}

:

class AnotherBadClass
{
    public AnotherBadClass(BadClass badClass)
    {
        someFlag = badClass.someFlag;
    }
    public bool someFlag;
}

说我想要测试:

public void AnotherBadClassConstructorTest()
{
    BadClass badClass = new BadClass();
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClass);
    Assert.IsNotNull(anotherBadClass);
}

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

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

如果归结到这一点,我可以告诉他们,他们要么让我修改现有的代码库,要么接受这个模块低于10%的覆盖率。

如何模拟c#中没有接口和虚方法的类

考虑到我不能修改我正在测试的代码,是否存在让它工作的直接方法是什么?

。但是,我看到了两个不直接的选项:

A)使用Microsoft Fakes通过重写库来提供mock。你不需要修改代码。例如:可以修改static DateTime。现在返回您选择的日期,像这样:
System.Fakes.ShimDateTime.NowGet = 
() =>
{ return new DateTime(fixedYear, 1, 1); };

B)你可以尝试继承被测试的类并覆盖使用的方法/函数。但是有两个限制。您必须能够用模拟对象实例化/交换被测试类的实例(通过使用反射,您可以获得私有成员),并且模拟方法必须是虚拟的。在您的示例中,您将创建:

class BadClassMock : BadClass
{
    public BadClassMock()
    {
    }
    public bool someFlag;
    public void InitForTest()
    {
        someFlag = true;
    }
}

只要不调用基构造函数,它就可以工作。你可以从这里使用nasty FormatterServices.GetUninitializedObject()技巧:在c#中使用反射

创建没有默认构造函数的类型实例

,后来:

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

是的,这是一个相当大的变通方法。显然,最好的方法是说服作者修改代码。

如果您不想更改代码以接受接口,您将需要使用TypeMock或JustMock来模拟这一点。两者都是付费的工具,我还没有找到一个免费的工具,可以做你想做的事情。我更喜欢JustMock。JustMock的语法如下所示:

public void AnotherBadClassConstructorTest()
{
    BadClassMock badClassMock = Mock.Create<BadClassMock>();
    AnotherBadClass anotherBadClass = new AnotherBadClass(badClassMock);
    Assert.IsNotNull(anotherBadClass);
}

如果你要经常这样做,或者想要测试没有使用单元测试编写的遗留代码,这些工具在我看来是值得的。你也可以免费试用一下

实际上,您可以在不修改代码的情况下模拟BadClass,通过使用TypeMock Isolator,您将能够模拟类,即使它不是虚拟的或接口。例如,下面是您尝试创建的测试:

[TestMethod]
public void CreateAnotherBadClass_IsNotNull()
{
    var fakeBadClass = Isolate.Fake.Instance<BadClass>();
    var anotherBadClass = new AnotherBadClass(fakeBadClass);
    Assert.IsNotNull(anotherBadClass);
}

在这个测试中,我创建了一个假的BadClass实例,并将其作为参数发送给AnotherBadClass c'tor。

相关文章: