我正在为别人的代码编写单元测试,我不允许修改.
说我有:
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%以下的覆盖率.
考虑到我无法修改我正在测试的代码,是否有一种直接的方法来使其工作?
不.但是,我看到两个非直截了当的选择:
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)
是的,这是一个非常大的解决方法.显然,最好的方法是说服作者修改代码.