我是Moq的新手。我正在模拟一个PagingOptions
类。下面是这个类的外观:
public class PagingOptions
{
[Range(1, 99999, ErrorMessage = "Offset must be greater than 0.")]
public int? Offset { get; set; }
[Range(1, 100, ErrorMessage = "Limit must be greater than 0 and less than 100.")]
public int? Limit { get; set; }
public PagingOptions Replace(PagingOptions newer)
{
return new PagingOptions
{
Offset = newer.Offset ?? Offset,
Limit = newer.Limit ?? Limit
};
}
}
这是这个类的模拟版本
var mockPagingOptions = new Mock<PagingOptions>();
mockPagingOptions.Setup(po => po.Limit).Returns(25);
mockPagingOptions.Setup(po => po.Offset).Returns(0);
我在设置属性值时得到了下面的错误。我做错了什么吗?看起来我不能模拟具体的类?只能模拟接口?请帮助。
谢谢你,阿卜杜勒
6条答案
按热度按时间g0czyy6m1#
Moq创建被模拟类型的一个实现。如果类型是一个接口,它创建一个实现接口的类。如果类型是一个类,它创建一个继承类,并且继承类的成员调用基类。但是为了这样做,它必须重写成员。如果一个类有不能被重写的成员(它们不是虚拟的、抽象的),那么Moq就不能覆盖它们来添加自己的行为。
在这种情况下,没有必要模仿
PagingOptions
,因为使用真实的的PagingOptions
很容易。请执行以下操作:
我们如何决定是否模拟某个东西?一般来说,如果我们不想在测试中包含具体的运行时实现,我们就模拟某个东西。我们想测试一个类,而不是同时测试两个类。
但是在这个例子中,
PagingOptions
只是一个保存一些数据的类,嘲笑它真的没有什么意义,它和实际的一样容易使用。kulphzqa2#
我也有同样的错误,但在我的例子中,我试图模拟类本身,而不是它的接口:
w8biq8rn3#
如果您是基于原始标题
Non-overridable members may not be used in setup / verification expressions
得出这个问题的,并且其他答案都没有帮助,那么您可能希望看看反射是否能够满足您的测试需求。假设您有一个类
Foo
,其属性定义为public int I { get; private set; }
如果你尝试了答案中的各种方法,其中很少有适合这种情况的,但是你可以使用.net反射来设置一个示例变量的值,并且仍然在代码中保持相当好的重构支持。
下面是使用privatesetter设置属性的代码片段:
我不建议在生产代码中使用这个方法。它在我的许多测试中被证明非常有用。我几年前发现了这个方法,但最近需要再次查找它,这是搜索结果的顶部。
pinkon5k4#
我想改进Scott's答案并给予一般答案
如果类型是一个类,它创建一个继承类,继承类的成员调用基类。但是为了做到这一点,它必须重写成员。如果一个类有不能被重写的成员(它们不是虚拟的,抽象的),那么Moq不能重写它们来添加自己的行为。
在我的情况下,我必须使 prop 虚拟化。所以对你的类代码的回答是:
使用相同:
jbose2ul5#
有时候,您可能使用第三方库中的类,该类具有可以直接设置或模拟的属性。
如果上面的答案不充分,您还可以直接调用setter方法,例如,当一个类具有名为“Id”的属性而没有可访问的setter时:
yc0p9oo06#
在我的例子中,我是在模拟一个非虚的公共方法,让这个方法虚化就可以了。
作为一个老Java开发者,我习惯了所有的公共方法都已经是虚的,没有必要单独标记为虚的,这样子类就可以覆盖它们,C#在这里就不一样了。
也许有人可以解释一下,在C#中,为了测试的目的,是否可以将生产代码中的公共方法标记为虚拟的。