生成同一个模拟的两个对象

时间:2017-04-24 07:32:29

标签: c# unit-testing mocking moq bdd

我在C#中使用MoQ进行一些单元测试/ BDD测试,而且我经常需要两次生成相同的对象(因为它可能会在字典中使用)。或者99%相同但只有不同的ID。

有没有办法克隆"模拟定义?或者生成具有相同定义的两个对象?

2 个答案:

答案 0 :(得分:0)

您应该创建一个辅助方法,该方法构造接受一些参数来构造Mock对象。

[Test]
public void MyTest()
{
    Mock<ITestObject> myMock = CreateObject(1);
    ITestObject obj = myMock.Object;
}

private Mock<ITestObject> CreateObject(int id)
{
    Mock<ITestObject> mock = new Mock<ITestObject>();
    mock.SetupGet(o => o.ID).Returns(id);
    return mock;
}

private interface ITestObject
{
    int ID { get; set; }
}

答案 1 :(得分:0)

如果你只是需要一组数据来进行单元测试,你也可以考虑像AutoFixture这样的东西。对于要模拟的类,它可以与Moq一起使用。你教AutoFixture如何创建YourClass,你甚至可以设置像#34这样的规则;我的ID应该是大写字母的字符串,不超过X的数量。&#34;

然后你只使用自动混合。

var fixture = new Fixture();
var tetsClasses = fixture.CreateMany<TestClass>();

这只是为了给你一个想法。你可以用它做更多但更多,它与Moq一起玩得很好。

另一种方法是使用数据构建器模式来创建数据。因此,您可以从简单的事情开始,并在发现有关如何构建数据的新边缘情况时继续添加。只需在其上构建一个流畅的API,然后根据需要构建数据。

internal class TestClassBuilder<T> : where T : TestClass
{
   int Id {get; set;}

   public T WithId(int id)
   {
     this.Id = id;
     return this;
   }

   public virtual T Build()
   {      
        return new T()
         {
           if(this.Id)
               Id = this.Id; // if you chose to set it, then assign it
           else
            Id = GetRandomId() // you can figure a solution here
         }
    }  
}

然后称之为:

var stubOne = TestClassBuilder.WithId(1).Build();

如果需要,您可以扩展它以构建列表。

我喜欢数据构建器上的流畅API,因为您可以开始用您创建的方法讲述您的故事,并使您的编辑部分保持整洁。 示例:

var UnderAgeCustomer = new CustomerBuilder
                        .UnderAge
                        .WithFakeId
                        .InACrowd
                        .LooksYoung
                        .Build()

你甚至可以加上

public static implicit operator T(TestClassBuilder<T> builder)
{
  return builder.Build();
}

并且您不需要一直使用.Build()部分(我认为构建会增加不必要的噪音)。只是不要尝试将其分配给var,它不会起作用。

TestClass MockTwo = TestClassBuilder.WithId(2);

我会说你也可以使用夹具模式跟踪所有这些...但是在它和数据库之间,你可以使用AutoFixture和Moq,如我所建议的那样:)