C# Moq 模拟部分方法但抛出 NotSupportedException
C# Moq mock partial methods but throw out NotSupportedException
我关注了这个问题 Using Moq to mock only some methods 但仍然抛出异常。
这是我的主要 class。 Foo
充当装饰器。
public class Foo {
public Bar _b {get; set;}
public Foo(Bar b) {
this._b = b;
}
public bool MyMethod(){
return ComplexMethod(_b.name);
}
public bool ComplexMethod(){
...
}
}
测试class
[TestClass]
public class Foo {
[TestMethod]
public void TestFoo() {
var b = new Bar() {name = "name"};
var mock = new Mock<Foo>(b);
mock.CallBase = true;
mock.Setup(x => x.ComplexMethod()).Returns(true);
var result = mock.Object.MyMethod();
...
}
}
抛出异常:
System.NotSupportedException: 'Unsupported expression: x =>
x.ComplexMethod() Non-overridable members (here: Foo.ComplexMethod)
may not be used in setup / verification expressions.'
您应该模拟依赖项而不是实际对象。所以,如果你想评估 MyMethod
of Foo
那么你应该模拟 Bar
.
为了能够模拟 Bar
的 name
成员:
- 您应该将其标记为
virtual
或 abstract
(ref)
- 或者你应该定义一个接口
我们来看后一种情况:
public interface IBar
{
string Name { get; }
}
public class Bar: IBar
{
public string Name { get; set; }
}
public class Foo
{
private readonly IBar _b;
public Foo(IBar b) {
this._b = b;
}
...
}
使用此设置,您的单元测试可能如下所示:
[TestMethod]
public void GivenABar_WhereTheNameIsEmpty_WhenICallMyMethod_ThenItReturnsTrue()
{
//Arrange
var barMock = new Mock<IBar>();
barMock.SetupGet(x => x.Name).Returns("");
//Act
var SUT = new Foo(barMock.Object);
var result = SUT.MyMethod();
//Assert
barMock.VerifyGet(m => m.Name, Times.Once);
Assert.True(result);
}
[TestMethod]
public void GivenABar_WhereTheNameIsNotEmpty_WhenICallMyMethod_ThenItReturnsFalse()
{
//Arrange
var barMock = new Mock<IBar>();
barMock.SetupGet(x => x.Name).Returns("test");
//Act
var SUT = new Foo(barMock.Object);
var result = SUT.MyMethod();
//Assert
barMock.VerifyGet(m => m.Name, Times.Once);
Assert.False(result);
}
更新:模拟 SUT 的一种方法
如果你只想模拟 Foo
的 ComplexMethod
那么你可以使用最小起订量的 As
.
const bool expectedResult = true;
var fooMock = new Mock<Foo>(barInstance).As<IFoo>();
fooMock.Setup(f => f.ComplexMethod()).Returns(expectedResult);
请注意,此技术仅在 Foo
实现 IFoo
时有效,这也公开了 ComplexMethod
public interface IFoo
{
bool MyMethod();
bool ComplexMethod();
...
}
public class Foo: IFoo
{
...
}
我关注了这个问题 Using Moq to mock only some methods 但仍然抛出异常。
这是我的主要 class。 Foo
充当装饰器。
public class Foo {
public Bar _b {get; set;}
public Foo(Bar b) {
this._b = b;
}
public bool MyMethod(){
return ComplexMethod(_b.name);
}
public bool ComplexMethod(){
...
}
}
测试class
[TestClass]
public class Foo {
[TestMethod]
public void TestFoo() {
var b = new Bar() {name = "name"};
var mock = new Mock<Foo>(b);
mock.CallBase = true;
mock.Setup(x => x.ComplexMethod()).Returns(true);
var result = mock.Object.MyMethod();
...
}
}
抛出异常:
System.NotSupportedException: 'Unsupported expression: x => x.ComplexMethod() Non-overridable members (here: Foo.ComplexMethod) may not be used in setup / verification expressions.'
您应该模拟依赖项而不是实际对象。所以,如果你想评估 MyMethod
of Foo
那么你应该模拟 Bar
.
为了能够模拟 Bar
的 name
成员:
- 您应该将其标记为
virtual
或abstract
(ref) - 或者你应该定义一个接口
我们来看后一种情况:
public interface IBar
{
string Name { get; }
}
public class Bar: IBar
{
public string Name { get; set; }
}
public class Foo
{
private readonly IBar _b;
public Foo(IBar b) {
this._b = b;
}
...
}
使用此设置,您的单元测试可能如下所示:
[TestMethod]
public void GivenABar_WhereTheNameIsEmpty_WhenICallMyMethod_ThenItReturnsTrue()
{
//Arrange
var barMock = new Mock<IBar>();
barMock.SetupGet(x => x.Name).Returns("");
//Act
var SUT = new Foo(barMock.Object);
var result = SUT.MyMethod();
//Assert
barMock.VerifyGet(m => m.Name, Times.Once);
Assert.True(result);
}
[TestMethod]
public void GivenABar_WhereTheNameIsNotEmpty_WhenICallMyMethod_ThenItReturnsFalse()
{
//Arrange
var barMock = new Mock<IBar>();
barMock.SetupGet(x => x.Name).Returns("test");
//Act
var SUT = new Foo(barMock.Object);
var result = SUT.MyMethod();
//Assert
barMock.VerifyGet(m => m.Name, Times.Once);
Assert.False(result);
}
更新:模拟 SUT 的一种方法
如果你只想模拟 Foo
的 ComplexMethod
那么你可以使用最小起订量的 As
.
const bool expectedResult = true;
var fooMock = new Mock<Foo>(barInstance).As<IFoo>();
fooMock.Setup(f => f.ComplexMethod()).Returns(expectedResult);
请注意,此技术仅在 Foo
实现 IFoo
时有效,这也公开了 ComplexMethod
public interface IFoo
{
bool MyMethod();
bool ComplexMethod();
...
}
public class Foo: IFoo
{
...
}