Moq,具有构造函数依赖性的调用库

时间:2015-11-05 18:16:43

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

我有一个班级

 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 [] overload:

[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类依赖。

2 个答案:

答案 0 :(得分:4)

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

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的依赖关系,以便它返回你的结果&#39之后。显然,您执行此操作的能力取决于方法的作用以及在必要时可以更改的代码量,有时候,特别是对于遗留代码,您只需使用您所拥有的内容即可。

答案 1 :(得分:1)

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

我建议创建以下内容

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

然后new FooForTest(barMock.Object)应该有用。