一个类中只允许使用一个方法

本文关键字:一个 许使用 方法 | 更新日期: 2023-09-27 18:11:48

我使用moq.dll当我模拟一个类(所有IRepository接口)时,我使用这行代码

   int state = 5;
   var rep = new Mock<IRepository>();
   rep.Setup(x => x.SaveState(state)).Returns(true);
   IRepository repository = rep.Object;

但是在这种情况下,我模拟了存储库类中的所有函数。然后用Mock dll

的方法设置替换类存储库中的所有方法。

我想使用类存储库(真正的类)中定义的所有方法,只模拟一个函数(SaveState)

我该怎么做?是可能的吗?

一个类中只允许使用一个方法

您可以创建实际存储库的实例,然后使用As<>()获得所需的接口,然后可以通过设置覆盖该接口,如下所示:

var mockRep = new Mock<RealRepository>(ctorArg1, ctorArg2, ...)
                     .As<IRepository>();
mockRep.Setup(x => x.SaveState(state)).Returns(true);

然后mockRep.Object作为被测类的存储库依赖。请注意,您只能以这种方式模拟Interface *上的方法或虚拟方法。

更新: *这可能不是在所有情况下工作,因为.Setup将只工作在虚拟方法上,c#接口实现是"虚拟"的,默认情况下是密封的。使用As()可以防止部分模拟行为。

因此,为了使部分模拟成功,RealRepository具体类似乎需要用虚拟方法实现IRepository接口,在这种情况下,可以使用CallBase进行连接。
   public interface IRepo
   {
      string Foo();
      string Bar();
   }
   public class RealRepo : IRepo
   {
      public RealRepo(string p1, string p2) {Console.WriteLine("CTOR : {0} {1}", p1, p2); }
      // ** These need to be virtual in order for the partial mock Setups
      public virtual string Foo() { return "RealFoo"; }
      public virtual string Bar() {return "RealBar"; }
   }
   public class Sut
   {
      private readonly IRepo _repo;
      public Sut(IRepo repo) { _repo = repo; }
      public void DoFooBar()
      {
         Console.WriteLine(_repo.Foo());
         Console.WriteLine(_repo.Bar());
      }
   }

   [TestFixture]
   public class SomeFixture
   {
      [Test]
      public void SomeTest()
      {
        var mockRepo = new Mock<RealRepo>("1st Param", "2nd Param");
        // For the partially mocked methods
        mockRepo.Setup(mr => mr.Foo())
           .Returns("MockedFoo");
        // To wireup the concrete class.
        mockRepo.CallBase = true;
        var sut = new Sut(mockRepo.Object);
        sut.DoFooBar();
      }
   }

我来到这个页面,因为我有完全相同的问题:我需要模拟一个方法,它依赖于许多外部源,可以产生三种输出中的一种,而让类的其余部分完成它的工作。不幸的是,上面提出的部分模拟方法不起作用。我真的不知道为什么不起作用。然而,主要的问题是,即使在需要的地方设置了断点,也无法在这样的模拟类中进行调试。这并不好,因为您可能真的需要调试某些东西。

因此,我使用了一个更简单的解决方案:将您想要模拟的所有方法声明为虚方法。然后从该类继承并编写一行模拟重写以返回所需内容,例如:

public class Repository
{
    /// <summary>
    /// Let's say that SaveState can return true / false OR throw some exception.
    /// </summary>
    public virtual bool SaveState(int state)
    {
        // Do some complicated stuff that you don't care about but want to mock.
        var result = false;
        return result;
    }
    public void DoSomething()
    {
        // Do something useful here and assign a state.
        var state = 0;
        var result = SaveState(state);
        // Do something useful with the result here.
    }
}
public class MockedRepositoryWithReturnFalse : Repository
{
    public override bool SaveState(int state) => false;
}
public class MockedRepositoryWithReturnTrue : Repository
{
    public override bool SaveState(int state) => true;
}
public class MockedRepositoryWithThrow : Repository
{
    public override bool SaveState(int state) => 
        throw new InvalidOperationException("Some invalid operation...");
}

。然后你可以在单元测试期间使用你的模拟仓库,并且你可以调试任何你需要的东西。您甚至可以将保护级别设置为低于公共级别,这样就不会暴露您不想暴露的内容。