在C# / .NET中模拟没有无参构造函数的对象

46

是否可以创建一个模拟类,该类不提供无参构造函数且不向构造函数传递任何参数?也许可以通过动态创建IL实现?

背景是我不想仅为测试目的而定义接口。解决方法是为测试提供一个无参构造函数。


同样,从使用Moq创建模拟的角度来说,您需要将方法设置为虚拟的。在这种情况下,接口通常更好。对于其他模拟框架不确定。 - Yuriy Faktorovich
3
理想情况下,应该在整个代码中使用接口而不是具体实现,因此,“仅为测试创建接口”的评论就没有意义了。请注意,我的翻译并未改变原文的含义,同时使其更加通俗易懂。 - Aaron McIver
10
我认为只有一个实现的接口是毫无价值的工具。 - deamon
在 C# 中进行测试时,您会发现需要创建一个接口。作为替代方案,您可以为方法/属性提供虚拟关键字,但是您会发现接口更好地表达了您的设计,并允许将具体实例与消费者更加解耦。 - Ritch Melton
2个回答

72

当然可以。在这个示例中,我将使用 Moq,一个真正很棒的模拟库。

示例:

public class MyObject
{
     public MyObject(object A, object B, object C)
     {
          // Assign your dependencies to whatever
     }
}

Mock<MyObject> mockObject = new Mock<MyObject>();
Mock<MyObject> mockObject = new Mock<MyObject>(null, null, null); // Pass Nulls to specific constructor arguments, or 0 if int, etc

在很多情况下,我会将模拟对象分配为参数,从而测试依赖关系:

Mock<Something> x = new Mock<Something>();
MyObject mockObject = new MyObject(x.Object);

x.Setup(d => d.DoSomething()).Returns(new SomethingElse());

etc

同意。Moq非常棒。他们在一个网页上提供了完整的如何参考指南。无法超越它的易用性和学习性。 - Ritch Melton
2
当构造函数需要非空值(使用代码合同或异常)时,它是否有效? - deamon
例如,如果你有一个整数,你可以传递一个0。如果它是一个字符串,则可以使用Null、string.Empty等值。你几乎可以使用default(T),其中T是你的参数类型,并且一切都能很好地处理。如果你正在创建一个模拟对象,标记为virtual的方法/属性永远不会被执行;你可以通过回调控制它们的行为,或者通过返回方法在模拟对象上控制它们的返回值。 - Tejs

2

错误的认为你只是为测试提供接口。接口存在的目的是提供抽象,并减弱代码不同层之间的耦合,使它们在不同上下文中更加可重用。

话虽如此,答案将取决于您使用的模拟框架。例如,使用Rhino Mocks,您可以有以下内容:

public class Foo
{
    public Foo(string bar)
    { }

    public virtual int SomeMethod()
    {
        return 5;
    }
}

然后:

var fooMock = MockRepository.GeneratePartialMock<Foo>("abc");
fooMock.Expect(x => x.SomeMethod()).Return(10);

1
这取决于你的观点:对于开发人员来说,编写接口以减弱耦合是正确的。但如果QA可以跳过这一步骤,他不想仅仅为了测试目的而“改进”功能代码。 - PPC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接