2016-09-06 44 views
2

我正在为我不允许修改的其他人的代码编写单元测试。如何在C#中不使用接口和虚拟方法来模拟一个类?

说我有:

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%以下的覆盖率。

+2

您可能需要使用像[Microsoft Fakes](https://msdn.microsoft.com/en-us/library/hh549175.aspx)这样的专业库来截取并重写将其重定向到的方法你的嘲笑。 –

+1

恐怕只有集成测试才是真正的选择,如果您无法触摸代码。 –

回答

4

考虑到我不能修改我的测试代码,有没有使这个工作 简单的方法?

否。但是,我看到两个,非简单的选择:

A)使用Microsoft Fakes通过重写库提供的嘲笑。您不必修改代码。例如:你可以修改静态DateTime.Now来回报您选择的日期如下:

System.Fakes.ShimDateTime.NowGet = 
() => 
{ return new DateTime(fixedYear, 1, 1); }; 

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

class BadClassMock : BadClass 
{ 
    public BadClassMock() 
    { 
    } 

    public bool someFlag; 

    public void InitForTest() 
    { 
     someFlag = true; 
    } 
} 

,它会工作,只要你不会调用基构造函数。您可以使用讨厌FormatterServices.GetUninitializedObject()招从这里:Creating instance of type without default constructor in C# using reflection

及更高版本:

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

是的,这是相当大的解决方法。显然最好的方法是说服作者修改代码。

+0

这可以工作,但它看起来像我可能无法带入假货。知道Moq中是否有类似的功能? – Damien

+0

Moq适用于不同级别。 Moq允许你使用继承,虚拟方法或接口创建模拟 - 它不能在编译的代码上工作,因此它不允许你模拟BadClass。有了Fakes,你只需将BadClass的编译代码交换到任何你想要的。您仍然可以尝试B选项。 – piotrwest

0

实际上,您可以在不修改代码的情况下模拟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。

+0

您应该补充一点,此功能在TypeMock Isolator中支付... – piotrwest

0

如果您不想更改接口中的代码,您将希望使用TypeMockJustMock来模拟此操作。两者都是付费工具,我还没有找到一个可以做你想做的事情的免费工具。我更喜欢JustMock。对于JustMock语法看起来像这样:

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

如果你打算做这个有很多还是想测试是没有考虑到单元测试旧代码,这些工具是非常值得的成本我意见。你总是可以免费试用,试试它们。

相关问题