[英]Moq - It.Is without having to specify all properties
我正在使用 Moq 来测试一个方法,被测方法将一个 json 字符串作为参数,将其反序列化为预期的类对象,并使用这个反序列化的类对象调用服务。
我想设置我的服务以期望有问题的类对象的实例具有正确的值,以便我可以验证将 json 字符串反序列化为类对象的步骤是否按预期工作。
目前,我正在使用It.Is<MyClass>(...)
方法,但这意味着我必须指定每个属性,并且一些预期的对象包含很多属性。
public class MyClassTests
{
private Mock<IMyService> _serviceMock = new Mock<IMyService>();
public void UnitTest01()
{
// Arrange
MyObject myObject = new MyObject
{
SomeProperty01 = "One",
SomeProperty02 = 2,
Timestamp = DateTime.Now
};
string input = Newtonsoft.Json.JsonConvert.SerializeObject(myObject);
// *** how can I improve this so I dont have to specify every property? ***
_serviceMock.Setup(x => x.DoSomething(It.Is<MyObject>(o =>
o.SomeProperty01 == myObject.SomeProperty01
&& o.SomeProperty02 == myObject.SomeProperty02
&& o.Timestamp == myObject.Timestamp
)));
MyClass myClass = new MyClass(_serviceMock.Object);
// Act
myClass.DoWork(input);
// Assert
_serviceMock.Verify();
}
}
// The class under test
public class MyClass
{
private readonly IMyService _myService;
public MyClass(IMyService myService)
{
_myService = myService;
}
// The method under test. I want to verify that deserialising works as expected,
// and that the service is called with the expected argument.
public void DoWork(string jsonString)
{
MyObject deserialised = Newtonsoft.Json.JsonConvert.DeserializeObject<MyObject>(jsonString);
_myService.DoSomething(deserialised);
}
}
public class MyService : IMyService
{
public void DoSomething(MyObject myObject)
{
// For the sake of this test, it doesnt matter what this service method does
}
}
public interface IMyService
{
void DoSomething(MyObject myObject);
}
public class MyObject
{
public string SomeProperty01 { get; set; }
public int SomeProperty02 { get; set; }
public DateTime Timestamp { get; set; }
// Loads more properties...
}
是否可以执行类似于It.Is<MyObject>()
,我不必指定每个属性? 一种解决方案可能是It.Is<MyObject>(o => o.Equal(myObject))
MyObject.Equals 方法,即It.Is<MyObject>(o => o.Equal(myObject))
。 但是,这并不理想,因为它涉及为了单元测试而更改代码。
考虑改变方法。 从模拟中捕获Callback
传递的参数,然后使用FluentAssertions断言它符合预期。
public class MyClassTests {
private Mock<IMyService> _serviceMock = new Mock<IMyService>();
public void UnitTest01() {
// Arrange
MyObject expected = new MyObject {
SomeProperty01 = "One",
SomeProperty02 = 2,
Timestamp = DateTime.Now
};
MyObject actual = null;
//Setup the mock to capture the passed argument in a callback
_serviceMock
.Setup(x => x.DoSomething(It.IsAny<MyObject>())
.Callback(MyObject arg => { actual = arg; });
MyClass myClass = new MyClass(_serviceMock.Object);
string input = Newtonsoft.Json.JsonConvert.SerializeObject(expected);
// Act
myClass.DoWork(input);
// Assert using FluentAssertions
actual.Should().BeEquivalentTo(expected);
}
}
现在无需更改测试对象即可进行测试。
您可以使用 KellermanSoftware.CompareNetObjects 库并为这样的对象创建扩展方法:
public static bool IsEqual<T>(this T value, T other, ComparisonConfig config = null)
{
var comparer = new CompareLogic();
if (config != null) comparer.Config = config;
var comparisonResult = comparer.Compare(value, other);
return comparisonResult.AreEqual;
}
然后你可以使用:
_serviceMock.Setup(x => x.DoSomething(It.Is<MyObject>(o => o.IsEqual(myObject)));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.