即使在 CallBase = true/false 之后,原始方法仍会在 Moq 中被调用
Original method still getting called in Moq even after CallBase = true/false
这是我的代码:
public class Bar { }
public class Foo { public string Name { get; set; } public Bar TheBar { get; set; } }
public class Dependency
{
public Foo DoSomething(Expression<Func<Foo, bool>> exp1) { return new Foo(); }
}
public class Base
{
public Dependency Dependency { get; set; }
public virtual Foo MethodA(Expression<Func<Foo, bool>> exp1,
params Expression<Func<Foo, object>>[] exp2)
{
return Dependency.DoSomething(exp1);
}
}
public class Derived : Base
{
public Foo DerviedMethod(string str)
{
return base.MethodA(e1 => e1.Name.Equals(str), e2 => e2.TheBar);
}
}
还有我的单元测试代码:
var mock = new Mock<Derived> { CallBase = true }; // Same result with false
mock
.Setup(m => m.MethodA(
It.IsAny<Expression<Func<Foo, bool>>>(),
It.IsAny<Expression<Func<Foo, object>>>()
))
.Returns(new Foo());
// Act
var result = mock.Object.DerviedMethod("test");
// Assert
Assert.IsNotNull(result);
但它仍然调用原始方法而不是模拟方法。 类 都存在于同一个程序集中。
我搜索了一下,几乎所有人都用 CallBase = true
或 false
找到了答案。
知道上面的代码有什么问题吗?
正如@Pierre-Luc 在评论中所建议的那样,提取基础 class 并将其作为依赖项注入可能是更好的方法(我一直认为嘲笑 class 你重新实际尝试测试感觉不对)。
就是说,要模拟 class 的调用,需要通过 VTable 进行。本质上,模拟框架创建了虚方法的新实现。当你正常调用时,这个版本的方法是运行,然后可以拦截调用。有问题的是这一行:
return base.MethodA(e1 => e1.Name.Equals(str), e2 => e2.TheBar);
因为您是通过 base
关键字显式调用 MethodA
,所以它告诉编译器调用该方法的特定版本。 总是 调用基础实现。这意味着模拟无法拦截调用。
将方法更改为:
public Foo DerviedMethod(string str) {
return MethodA(e1 => e1.Name.Equals(str), e2 => e2.TheBar);
}
允许模拟 MethodA
方法。从设计的角度来看,这是否正确取决于您。
这是我的代码:
public class Bar { }
public class Foo { public string Name { get; set; } public Bar TheBar { get; set; } }
public class Dependency
{
public Foo DoSomething(Expression<Func<Foo, bool>> exp1) { return new Foo(); }
}
public class Base
{
public Dependency Dependency { get; set; }
public virtual Foo MethodA(Expression<Func<Foo, bool>> exp1,
params Expression<Func<Foo, object>>[] exp2)
{
return Dependency.DoSomething(exp1);
}
}
public class Derived : Base
{
public Foo DerviedMethod(string str)
{
return base.MethodA(e1 => e1.Name.Equals(str), e2 => e2.TheBar);
}
}
还有我的单元测试代码:
var mock = new Mock<Derived> { CallBase = true }; // Same result with false
mock
.Setup(m => m.MethodA(
It.IsAny<Expression<Func<Foo, bool>>>(),
It.IsAny<Expression<Func<Foo, object>>>()
))
.Returns(new Foo());
// Act
var result = mock.Object.DerviedMethod("test");
// Assert
Assert.IsNotNull(result);
但它仍然调用原始方法而不是模拟方法。 类 都存在于同一个程序集中。
我搜索了一下,几乎所有人都用 CallBase = true
或 false
找到了答案。
知道上面的代码有什么问题吗?
正如@Pierre-Luc 在评论中所建议的那样,提取基础 class 并将其作为依赖项注入可能是更好的方法(我一直认为嘲笑 class 你重新实际尝试测试感觉不对)。
就是说,要模拟 class 的调用,需要通过 VTable 进行。本质上,模拟框架创建了虚方法的新实现。当你正常调用时,这个版本的方法是运行,然后可以拦截调用。有问题的是这一行:
return base.MethodA(e1 => e1.Name.Equals(str), e2 => e2.TheBar);
因为您是通过 base
关键字显式调用 MethodA
,所以它告诉编译器调用该方法的特定版本。 总是 调用基础实现。这意味着模拟无法拦截调用。
将方法更改为:
public Foo DerviedMethod(string str) {
return MethodA(e1 => e1.Name.Equals(str), e2 => e2.TheBar);
}
允许模拟 MethodA
方法。从设计的角度来看,这是否正确取决于您。