如何在没有接口的情况下模拟类?

我正在 Windows 7中使用 C # 开发.NET 4.0。

I want to test the communication between some methods using mock. The only problem is that I want to do it without implementing an interface. Is that possible?

我只是阅读了很多关于模拟对象的主题和一些教程,但它们都用于模拟接口,而不是类。我尝试使用 Rhino 和 Moq 框架。

147454 次浏览

只需将需要伪造的任何方法标记为 virtual(而不是 private)。然后你就可以创建一个假的来覆盖这个方法。

如果您使用的是 new Mock<Type>,并且没有无参数构造函数,那么您可以将参数作为上述调用的参数传递,因为它的类型为 param Objects

使用 MoQ,您可以模拟具体的类:

var mocked = new Mock<MyConcreteClass>();

但这允许您重写 virtual代码(方法和属性)。

大多数模拟框架(包括 Moq 和 RhinoMocks)生成代理类作为模拟类的替代品,并用您定义的行为覆盖虚拟方法。因此,您只能在具体或抽象类上模拟接口或虚方法。此外,如果要模仿具体的类,几乎总是需要提供一个无参数构造函数,以便模仿框架知道如何实例化该类。

Why the aversion to creating interfaces in your code?

标准的模仿框架正在创建代理类。这就是为什么它们在技术上仅限于接口和虚方法的原因。

如果您也想模仿“普通”方法,那么您需要一个使用检测而不是代理生成的工具。例如,MS 鼹鼠和 Typemock 可以做到这一点。但是前者有一个可怕的“ API”,而后者是商业化的。

如果你不能改变类测试,那么唯一的选择,我可以建议是使用微软假 https://msdn.microsoft.com/en-us/library/hh549175.aspx。 然而,MS Fakes 只能在 VisualStudio 的少数版本中工作。

我认为最好为这个类创建一个接口,并使用接口创建一个单元测试。

If it you don't have access to that class, you can create an adapter for that class.

例如:

public class RealClass
{
int DoSomething(string input)
{
// real implementation here
}
}


public interface IRealClassAdapter
{
int DoSomething(string input);
}


public class RealClassAdapter : IRealClassAdapter
{
readonly RealClass _realClass;


public RealClassAdapter() => _realClass = new RealClass();


int DoSomething(string input) => _realClass.DoSomething(input);
}

通过这种方式,您可以使用 IRealClassAdapter 轻松地为您的类创建 mock。

希望有用。

如果情况变得更糟,您可以创建一个接口和适配器对。 您可以将 ConcreteClass 的所有用法改为使用接口,并总是在生产代码中传递适配器而不是具体类。

适配器实现接口,因此模拟也可以实现接口。

这不仅仅是创建一个虚拟的方法或者添加一个接口,而是更多的脚手架,但是如果你不能访问具体类的源代码,它可以让你摆脱绑定。

I faced something like that in one of the old and legacy projects that i worked in that not contains any interfaces or best practice and also it's too hard to enforce them build things again or refactoring the code due to the maturity of the project business, So in my UnitTest project i used to create a Wrapper over the classes that I want to mock and that wrapper implement interface which contains all my needed methods that I want to setup and work with, Now I can mock the wrapper instead of the real class.

例如:

要测试不包含虚方法或实现接口的服务

public class ServiceA{


public void A(){}


public String B(){}


}

包装纸拿给 Moq

public class ServiceAWrapper : IServiceAWrapper{


public void A(){}


public String B(){}


}

包装器接口

public interface IServiceAWrapper{


void A();


String B();


}

在单元测试中,您现在可以模仿包装器:

    public void A_Run_ChangeStateOfX()
{
var moq = new Mock<IServiceAWrapper>();
moq.Setup(...);
}

This might be not the best practice, but if your project rules force you in this way, do it. Also Put all your Wrappers inside your Unit Test project or Helper project specified only for the unit tests in order to not overload the project with unneeded wrappers or adaptors.

更新: 这个答案来自一年多以前,但是在今年我面对了很多类似的情况和不同的解决方案。 例如,使用 Microsoft Fake Framework 创建模拟、假冒和存根,甚至在没有任何接口的情况下测试私有和受保护的方法是如此容易。 You can read: https://learn.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes?view=vs-2017

这是一个有点老的问题,但不管怎样。现在有一些强大的 Mocking 框架能够支持 模仿混凝土教室,比如 JustMock 和 Typemock。