Moq - 不可覆盖的成员不得用于设置/验证表达式
Moq - Non-overridable members may not be used in setup / verification expressions
我是最小起订量的新手。我在嘲笑 PagingOptions
class。这是 class 的样子:
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
};
}
}
这是我的模拟版本 class,
var mockPagingOptions = new Mock<PagingOptions>();
mockPagingOptions.Setup(po => po.Limit).Returns(25);
mockPagingOptions.Setup(po => po.Offset).Returns(0);
设置 属性 值时出现以下错误。我做错了什么吗?看起来我不能具体起订量 class?只能模拟接口吗?请协助。
谢谢,
阿卜杜勒
Moq 创建模拟类型的实现。如果类型是接口,它会创建一个 class 来实现该接口。如果类型是 class,它会创建一个继承的 class,并且继承的 class 的成员调用基类 class。但为了做到这一点,它必须覆盖成员。如果 class 具有无法覆盖的成员(它们不是虚拟的、抽象的),则 Moq 无法覆盖它们以添加自己的行为。
在这种情况下,无需模拟 PagingOptions
,因为它很容易使用真实的。而不是这个:
var mockPagingOptions = new Mock<PagingOptions>();
mockPagingOptions.Setup(po => po.Limit).Returns(25);
mockPagingOptions.Setup(po => po.Offset).Returns(0);
这样做:
var pagingOptions = new PagingOptions { Limit = 25, Offset = 0 };
我们如何确定是否要模拟某些东西?一般来说,如果我们不想在测试中包含具体的运行时实现,我们就会模拟一些东西。我们想测试一个 class 而不是同时测试两个。
但在这种情况下 PagingOptions
只是一个保存一些数据的 class。嘲笑它真的没有意义。使用真实的东西也一样容易。
我有同样的错误,但在我的例子中,我试图模拟 class 本身而不是它的接口:
// Mock<SendMailBLL> sendMailBLLMock = new Mock<SendMailBLL>(); // Wrong, causes error.
Mock<ISendMailBLL> sendMailBLLMock = new Mock<ISendMailBLL>(); // This works.
sendMailBLLMock.Setup(x =>
x.InsertEmailLog(
It.IsAny<List<EmailRecipient>>(),
It.IsAny<List<EmailAttachment>>(),
It.IsAny<string>()));
我想改进Scott's答案并给出一般答案
If the type is a class, it creates an inherited class, and the members of that inherited class call the base class. But in order to do that it has to override the members. If a class has members that can't be overridden (they aren't virtual, abstract) then Moq can't override them to add its own behaviors.
在我的情况下,我不得不将道具虚拟化。因此,您的 class 代码的答案是:
public class PagingOptions {
[Range (1, 99999, ErrorMessage = "Offset must be greater than 0.")]
public virtual int? Offset { get; set; }
[Range (1, 100, ErrorMessage = "Limit must be greater than 0 and less than 100.")]
public virtual 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);
如果你根据原标题Non-overridable members may not be used in setup / verification expressions
和none的其他答案得到了帮助,你可能想看看反射是否能满足你的测试需求。
假设您有一个 class Foo
,其中 属性 定义为 public int I { get; private set; }
如果您尝试此处答案中的各种方法,其中很少有方法适用于这种情况。但是,您可以使用 .net 反射来设置实例变量的值,并且仍然在代码中保持相当好的重构支持。
这是设置 属性 和 private setter:
的片段
var foo = new Foo();
var I = foo.GetType().GetProperty(nameof(Foo.I), BindingFlags.Public | BindingFlags.Instance);
I.SetValue(foo, 8675309);
我不建议将此用于生产代码。它在我的无数测试中被证明非常有用。我几年前发现了这种方法,但最近需要再次查找,这是最热门的搜索结果。
我是最小起订量的新手。我在嘲笑 PagingOptions
class。这是 class 的样子:
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
};
}
}
这是我的模拟版本 class,
var mockPagingOptions = new Mock<PagingOptions>();
mockPagingOptions.Setup(po => po.Limit).Returns(25);
mockPagingOptions.Setup(po => po.Offset).Returns(0);
设置 属性 值时出现以下错误。我做错了什么吗?看起来我不能具体起订量 class?只能模拟接口吗?请协助。
谢谢, 阿卜杜勒
Moq 创建模拟类型的实现。如果类型是接口,它会创建一个 class 来实现该接口。如果类型是 class,它会创建一个继承的 class,并且继承的 class 的成员调用基类 class。但为了做到这一点,它必须覆盖成员。如果 class 具有无法覆盖的成员(它们不是虚拟的、抽象的),则 Moq 无法覆盖它们以添加自己的行为。
在这种情况下,无需模拟 PagingOptions
,因为它很容易使用真实的。而不是这个:
var mockPagingOptions = new Mock<PagingOptions>();
mockPagingOptions.Setup(po => po.Limit).Returns(25);
mockPagingOptions.Setup(po => po.Offset).Returns(0);
这样做:
var pagingOptions = new PagingOptions { Limit = 25, Offset = 0 };
我们如何确定是否要模拟某些东西?一般来说,如果我们不想在测试中包含具体的运行时实现,我们就会模拟一些东西。我们想测试一个 class 而不是同时测试两个。
但在这种情况下 PagingOptions
只是一个保存一些数据的 class。嘲笑它真的没有意义。使用真实的东西也一样容易。
我有同样的错误,但在我的例子中,我试图模拟 class 本身而不是它的接口:
// Mock<SendMailBLL> sendMailBLLMock = new Mock<SendMailBLL>(); // Wrong, causes error.
Mock<ISendMailBLL> sendMailBLLMock = new Mock<ISendMailBLL>(); // This works.
sendMailBLLMock.Setup(x =>
x.InsertEmailLog(
It.IsAny<List<EmailRecipient>>(),
It.IsAny<List<EmailAttachment>>(),
It.IsAny<string>()));
我想改进Scott's答案并给出一般答案
If the type is a class, it creates an inherited class, and the members of that inherited class call the base class. But in order to do that it has to override the members. If a class has members that can't be overridden (they aren't virtual, abstract) then Moq can't override them to add its own behaviors.
在我的情况下,我不得不将道具虚拟化。因此,您的 class 代码的答案是:
public class PagingOptions {
[Range (1, 99999, ErrorMessage = "Offset must be greater than 0.")]
public virtual int? Offset { get; set; }
[Range (1, 100, ErrorMessage = "Limit must be greater than 0 and less than 100.")]
public virtual 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);
如果你根据原标题Non-overridable members may not be used in setup / verification expressions
和none的其他答案得到了帮助,你可能想看看反射是否能满足你的测试需求。
假设您有一个 class Foo
,其中 属性 定义为 public int I { get; private set; }
如果您尝试此处答案中的各种方法,其中很少有方法适用于这种情况。但是,您可以使用 .net 反射来设置实例变量的值,并且仍然在代码中保持相当好的重构支持。
这是设置 属性 和 private setter:
的片段var foo = new Foo();
var I = foo.GetType().GetProperty(nameof(Foo.I), BindingFlags.Public | BindingFlags.Instance);
I.SetValue(foo, 8675309);
我不建议将此用于生产代码。它在我的无数测试中被证明非常有用。我几年前发现了这种方法,但最近需要再次查找,这是最热门的搜索结果。