1

我已经为单元测试制作了一个通用数据构建器,因为我厌倦了一次又一次地实现构造函数和 Build 方法。这是否掩盖了图案的美丽(我真的很喜欢)?

这是我的通用构建器(在 C# 中使用 Moq 构建):

public class GenericMockBuilder<T> where T: class
{
    private readonly Mock<T> _objectMock = new Mock<T>(); 

    protected Mock<T> ObjectMock
    {
        get { return _objectMock; }
    }

    public T Build()
    {
        return _objectMock.Object; 
    }
}

这是一个示例接口及其继承通用接口的具体构建器:

public interface IFoo
{
    int Bar();
}

public class FooBuilder: GenericMockBuilder<IFoo>
{
    public FooBuilder WithBar(int barValue)
    {
        base.ObjectMock.Setup(x => x.Bar()).Returns(barValue);
        return this;
    }

}

构建器将像这样构造一个 foo 模拟:

        IFoo fooMock = new FooBuilder().WithBar(12).Build();

我很想听听意见和改进建议。

编辑(添加了 Eventraising 示例):

public class FooBuilderWithEvent: GenericMockBuilder<IFoo>
{

    public FooBuilderWithEvent RaiseEvent(FooEventArgs fooEventArgs)
    {
        base.ObjectMock.Raise(m => m.FooEvent += null, fooEventArgs); 
        return this; 
    }

}

Building Mock and raise 事件如下所示:

        FooBuilderWithEvent fooBuilderWithEvent = new FooBuilderWithEvent(); 
        IFoo fooMock = fooBuilderWithEvent.Build();

        //Create testobject and prepare for event here

        fooBuilderWithEvent.RaiseEvent(new FooEventArgs()); 
4

2 回答 2

1

优点

  • 漂亮的特定领域的流畅界面

缺点

  • 另一个没有人熟悉的界面(我和我认为许多其他开发人员在使用 Moq 标准流畅界面的模拟设置中没有看到任何复杂的东西)
  • 为每个模拟接口创建构建器类(是的,您只能为复杂的模拟创建构建器,但是使用两个不同的模拟接口可能会使开发人员感到困惑)
  • 为每个模拟成员创建设置方法

不知道您为什么要求 Moq 示例,因为您已经在构建器中拥有了所有这些代码:

var mock = new Mock<IFoo>();
mock.Setup(foo => foo.Bar()).Returns(42);

如果您对 lambda 和mock.Object调用感到困惑,请尝试 RhinoMocks:

Exect.Call(foo.Bar()).Return(42);

另外我有一个问题 -你将如何只使用模拟对象实例来引发事件?

于 2012-10-30T12:44:57.123 回答
0

必须在模拟框架上构建外观表明它不适合您。为什么不尝试另一个。我个人已从 Moq 切换到 NSubstitute:

你自己的例子:

IFoo fooMock = Substitute.For<IFoo>();
fooMock.WithBar(12).Returns(10);

或者,如果您只想检查该方法是否被调用:

//arrange
IFoo fooMock = Substitute.For<IFoo>(); 

//act
fooMock.WithBar(12);

//assert
fooMock.Received().WithBar(12);
于 2012-10-30T16:06:24.910 回答