【问题标题】:Moq, call base with constructor dependencies起订量,具有构造函数依赖项的调用库
【发布时间】:2015-11-05 18:16:43
【问题描述】:

我有课

 public class Foo 
 {
      public Foo(IBar bar)
      {
         //...
      }
      public virtual int GetValue(){}
      public virtual DoActual()
      {
           ...
         var value = GetValue();
           ...
      }
 }

我需要测试一下。我想覆盖 GetValue 方法并将特定值返回给调用者。 这是我的测试代码:

[TestMethod]
public void Test()
{
    var mock = new Mock<Foo>{ CallBase=true}; // problem is here
    mock.Setup(x=>x.GetValue()).Returns(1); 

    mock.DoActual();

 //asserts
}

由于我的 Foo 类构造函数具有依赖项,我必须将其传递给对象初始化程序。 Moq 提供将参数传递给 params[] 重载:

[TestMethod]
public void Test()
{
   var barMock= new Mock<IBar>();
    var mock = new Mock<Foo>(barMock){ CallBase=true}; // problem is still here
    mock.Setup(x=>x.GetValue()).Returns(1); 
    mock.DoActual();
 //asserts
}

当我以这种方式传递我的模拟时,我收到错误消息说 Moq.Mock`1[IBar] 不是 Foo 接受的构造函数。

当我将 barMock.Object 传递给构造函数时,我得到了不同类型的基本相同的错误:

"Could not find a constructor that would match given arguments:
 Castle.Proxies.IBarProxy"

我卡在这个地方,不知道如何解决我的 Foo 类依赖项。

【问题讨论】:

  • barMock.Object 传递给构造函数,而不是barMock
  • 请仔细阅读我的问题,这个方法我试过了
  • 所以您基本上是想测试DoActual 调用GetValue?测试的意义何在?
  • 测试点不是个案。我在样本中添加了点,目的是只突出我的问题。我知道我的代码是“不良做法”书的一个很好的例子,但我目前无法重构它。现在我只需要写测试。
  • 你试过简单地将它传递给 null 吗?

标签: c# .net unit-testing mocking moq


【解决方案1】:

您上面最小化的问题无法编译,这表明您尚未以当前形式对其进行测试。这使得很难判断您的实际问题是否被正确描述,或者您是否将问题减少得太远并删除了您的实际问题,在这种情况下,您可能需要编辑您的问题以包含更多详细信息。下面的代码,基于上面的编译和工作。

public interface IBar {
}

public class Foo 
{
   public Foo(IBar bar)
   {
       //...
   }
   public virtual int GetValue(){ return 0;}
   public virtual void DoActual()
   {
       var value = GetValue();
   }
}

[TestFixture]
public class SomeTests {
    [Test]
    public void TestMethodCalled() {
        var barMock = new Mock<IBar>();
        var mock = new Mock<Foo>(barMock.Object) { CallBase = true };
        mock.Setup(x => x.GetValue()).Returns(1);
        mock.Object.DoActual();
        //asserts
        mock.Verify(x => x.GetValue());
    }
}

它将barMock.Object传递给构造函数,并验证该方法是否已被调用。

正如已经说过的,模拟您正在测试的类通常是一个坏主意,更好的方法是操纵/模拟GetValue 的依赖关系,以便它返回您所追求的结果。显然,您执行此操作的能力将取决于该方法的作用以及在必要时可以更改多少代码,有时,尤其是对于遗留代码,您只需要使用现有的代码即可。

【讨论】:

  • 酷,谢谢。我尝试了相同的方法,但由于上面提到的原因失败了。看起来这是一个正确的方法。我必须检查我的代码以找出它不起作用的原因。
【解决方案2】:

一般来说,您应该创建要测试的类(被测系统,SUT)的依赖项的模拟,而不是 SUT 本身。

我建议创建以下内容

public class FooForTest : Foo
{
      public FooForTest(IBar bar) : base(bar) {}
      public override int GetValue() { return 1; }
}

那么new FooForTest(barMock.Object) 应该可以工作了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多