我正在尝试为模拟(模型)定义返回值。
任何人都可以向我解释为什么以下代码因“不可覆盖的成员上的无效设置”而失败:
model.SetupGet(x => x.PostCodeSearch).Returns(It.IsAny<string>);
然而我能做到这一点并且工作正常:
model.Object.PostCodeSearch = "Any value as long as it's not null or empty";
错误消息足够清楚但似乎很奇怪我可以直接在Object属性上将值应用于属性。如果我可以做后者,那么SetUpGet有什么意义呢?
答案 0 :(得分:1)
确保在伪造类型上声明PostCodeSearch
virtual
。
public virtual string PostCodeSearch { get; set; }
moq 只能伪造可覆盖的属性。
编辑:处理非可覆盖的
如果伪造的类型无法更改,则有不同的选择:
更改生产代码以使用伪造类的包装。包装器将具有与包装类相同的API,它所做的就是将调用路由到包装对象。包装器将方法和属性声明为virtual
。这样,您在代码中获得的行为几乎没有变化。
例如,如果伪造的原始类是MyClass:
public class MyClassWrapper
{
MyClass myClass;
MyClassWrapper(MyClass myClass)
{
this.myClass = myClass;
}
public virtual string PostCodeSearch
{
get { return myClass.PostCodeSearch; }
set { myClass.PostCodeSearch = value; };
}
}
生产代码将使用MyClassWrapper
代替MyClass
,并且使用这一点变化可以使代码可测试。
另一种选择是使用隔离框架。隔离框架可以伪造不可覆盖的成员,静态成员,密封类......
例如,使用Typemock Isolator:
MyClass myClass = new MyClass();
Isolate.WhenCalled(() => myClass.PostCodeSearch).WillReturn("faked value");
在此示例中,伪造行为直接在原始类上设置。这里的优点是生产代码中不需要进行任何更改以使其可测试。
免责声明 - 我在Typemock工作