[英]Mock a property of an object to return a value that is coming from the object itself
我想用对象返回一个属性的模拟,该对象返回一个属性,该值来自同一模拟实例的另一个属性,但是我找不到如何使用Moq进行设置。
我为Setup / SetupGet找到的所有签名都只允许返回常量值,而不能返回来自同一对象的值。
范例:
void Main()
{
var obj = GetMock().Object;
obj.PropA = "test";
Console.WriteLine(obj.Id); // Should return -354185609, as it's the result of "test".GetHashCode()
obj.PropA = "test 2";
Console.WriteLine(obj.Id); // Should return -1555281747, as it's the result of "test 2".GetHashCode()
}
public interface IMyObject
{
int Id { get;set;}
string PropA {get; set;}
}
public Mock<IMyObject> GetMock()
{
var objectMock = new Mock<IMyObject>();
objectMock.SetupAllProperties();
objectMock
.SetupGet((IMyObject s) => s.Id)
//Here I would like to write something like :
.Returns(s => (a.PropA?.GetHashCode()).GetValueOrDefault()));
// To have the Getter of Id initialized with the current value of PropA.GetHashCode()
return objectMock;
}
谢谢你的建议
您可以使用Callback
来存储set
值,然后在Returns
重新使用它。 像这样:
string propA = null;
var mock = new Mock<IMyObject>();
mock.SetupSet(m => m.PropA = It.IsAny<string>())
.Callback<string>(s => propA = s);
mock.Setup(m => m.Id)
.Returns(() => (propA?.GetHashCode()).GetValueOrDefault());
mock.Object.PropA = "test";
Assert.Equal("test".GetHashCode(), mock.Object.Id);
mock.Object.PropA = "test 2";
Assert.Equal("test 2".GetHashCode(), mock.Object.Id);
另一个选择是具有实际的实现并使用CallBase
功能。 (类似答案 )
public abstract class MyObjectDummy : IMyObject
{
public virtual int Id { get; set; }
public virtual string PropA { get; set; }
}
var mock = new Mock<MyObjectDummy>();
mock.SetupSet(m => m.PropA = It.IsAny<string>()).CallBase();
mock.SetupGet(m => m.PropA).CallBase();
mock.Setup(m => m.Id).Returns(() => (mock.Object.PropA?.GetHashCode()).GetValueOrDefault());
mock.Object.PropA = "test";
Assert.Equal("test".GetHashCode(), mock.Object.Id);
有时Moq设置很难阅读,经常到其他人很难说出正在测试什么的程度。 在这些情况下,我们经常可以使用测试double(即实现接口的类)来“模拟”。
这是一个例子。 我不能肯定地说这是否可以解决您的模拟问题,但这确实是重点。 阅读该设置并告诉其功能并不容易。 另一方面,很容易看出它的作用:
public class ObjectWhereIdReturnsPropAHashCode : IMyObject
{
public int Id
{
get => PropA?.GetHashCode() ?? 0;
set => Id = value;
}
public string PropA { get; set; }
}
...然后创建执行相同操作的Mock<IObject>
要容易得多。
当创建测试双精度型的实例时,类的名称可以清楚地表明该测试双精度型针对特定测试的目的。 (公平地说,您也可以使用Moq来做到这一点,方法是创建一个命名函数来创建并返回该模拟。)
对于下一个必须创建新的测试双精度或修改现有测试双精度的开发人员而言,这也是一种更容易遵循的模式。
我并不是在建议我们不要一直使用Moq(我一直都在使用它),而只是在它变得不必要地复杂时我们应该研究替代方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.