生成相同模拟的两个对象
Generate two object of the same mock
我在 C# 中使用 MoQ 来做一些单元 tests/BDD 测试,我经常需要生成相同的对象两次(因为它可能会在字典中使用)。或者 99% 相同但 ID 不同的东西。
有没有办法 "clone" Mock 定义?或者生成两个具有相同定义的对象?
您应该创建一个辅助方法来构造它,该方法接受一些参数来构造 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; }
}
如果你只需要一组数据来进行单元测试,你也可以考虑像 AutoFixture 这样的东西。如果您想模拟 类,它可以与 Moq 一起使用。您教 AutoFixture 如何创建 YourClass,您甚至可以设置像 "my IDs should be strings with capital letters and no more than X amount of them."
这样的规则
那你就用autofixture.
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();
如果需要,您可以扩展它来构建列表。
我喜欢数据生成器上的流利 APIs,因为您可以开始使用您创建的方法来讲述您的故事,并且它使您的排列部分保持整洁。
示例:
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 :)
我在 C# 中使用 MoQ 来做一些单元 tests/BDD 测试,我经常需要生成相同的对象两次(因为它可能会在字典中使用)。或者 99% 相同但 ID 不同的东西。
有没有办法 "clone" Mock 定义?或者生成两个具有相同定义的对象?
您应该创建一个辅助方法来构造它,该方法接受一些参数来构造 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; }
}
如果你只需要一组数据来进行单元测试,你也可以考虑像 AutoFixture 这样的东西。如果您想模拟 类,它可以与 Moq 一起使用。您教 AutoFixture 如何创建 YourClass,您甚至可以设置像 "my IDs should be strings with capital letters and no more than X amount of them."
这样的规则那你就用autofixture.
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();
如果需要,您可以扩展它来构建列表。
我喜欢数据生成器上的流利 APIs,因为您可以开始使用您创建的方法来讲述您的故事,并且它使您的排列部分保持整洁。 示例:
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 :)