【问题标题】:Original method still getting called in Moq even after CallBase = true/false即使在 CallBase = true/false 之后,原始方法仍然在 Moq 中被调用
【发布时间】:2015-07-03 05:03:57
【问题描述】:

这是我的代码:

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 = truefalse 找到了它。

你知道上面的代码有什么问题吗?

【问题讨论】:

  • 你的Derived方法不应该标记为virtual吗?否则我认为你不能正确地模拟具体的课程。不确定。
  • 我已将其标记为 virtual 但现在它返回 null 而不是 bar 实例
  • 问题可能来自您的Setup。您可以尝试通过去除更多绒毛来找出问题所在,例如各种Expressions 参数和泛型以深入核心。无法让您的示例在我这边编译。
  • 我也没有,看起来这可能是起订量无法做到的。 this one 之类的类似答案/cmets 似乎得出了相同的结论。将您的架构从继承更改为组合(以便 Derive 有一个 Base 实例,而不是从它继承)可能会解决您的问题。这样你就可以直接模拟 Base 类并将你的模拟传递给你的 Derived 类。
  • 您还没有包含DoTest 所做的事情,但是您不能像当前编写的那样模拟代码。您通过 base. 说明符调用您尝试模拟的方法,该说明符告诉实现运行特定版本的函数。任何虚拟声明都会被忽略,因此不能被 Moq 截获。这基本上与我在此答案中讨论的问题相同(对 Moq 和 NSubstitute 的限制对此相同)stackoverflow.com/a/31062287/592182

标签: c# unit-testing moq-3


【解决方案1】:

正如@Pierre-Luc 在 cmets 中所建议的那样,提取基类并将其作为依赖项注入可能是更好的方法(我一直认为模拟您实际尝试测试的类感觉不对)。

也就是说,为了能够模拟一个类的调用,它需要通过 VTable 进行。本质上,模拟框架创建了虚拟方法的新实现。当你正常调用它时,这个版本的方法会运行,然后可以拦截调用。有问题的行是这一行:

return base.MethodA(e1 => e1.Name.Equals(str), e2 => e2.TheBar);

因为您通过base 关键字显式调用MethodA,它告诉编译器调用特定版本的方法。 总是会调用基本实现。这意味着 mock 无法拦截调用。

将方法更改为:

public Foo DerviedMethod(string str) {
    return MethodA(e1 => e1.Name.Equals(str), e2 => e2.TheBar);
}

允许模拟 MethodA 方法。从设计的角度来看,这是否正确取决于您。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-23
    • 2022-09-24
    • 2018-04-02
    相关资源
    最近更新 更多