moq only one method in a class

大憨熊 提交于 2020-01-31 06:44:44

问题


I'm using moq.dll When I mock a class(all the IRepository interface) i use this line code

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

but in this case i mock all the function in repository class. Then all the methods in class repository are substituted with the methods setup of Mock dll

I want use all the methods defined in class repository(the real class) and mock only one function(SaveState)

How can I do this? Is possible?


回答1:


You can create an instance of the real repository, then use the As<>() to obtain the desired interface, which you can then override with the setup, like this:

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

Then mockRep.Object as the repository dependency to the class under test. Note that you will only be able to Mock methods on the Interface*, or virtual methods, in this way.

Update : *This might not work in all scenarios, since .Setup will only work on virtual methods, and C# interface implementations are "virtual" and sealed by default. And using As() will prevent the partial mock behaviour.

So it appears that the RealRepository concrete class will need to implement the IRepository interface with virtual methods in order for the partial mock to succeed, in which case CallBase can be used for the wire-up.

   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();
      }
   }



回答2:


I came to this page because I had exactly the same problem: I needed to mock a single method, which was relying on many external sources and could produce one of three outputs, while letting the rest of the class do its work. Unfortunately the partial mock approach proposed above did not work. I really don't know why it did not work. However, the main problem is that you can't debug inside such mocked class even if you put break points where you want. This is not good because you might really need to debug something.

So, I used a much simpler solution: Declare all methods that you want to mock as virtual. Then inherit from that class and write one-liner mock overrides to return what you want, for example:

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...");
}

That's all. You can then use your mocked repos during unit tests AND you can debug anything you need. You can even leave the protection level below public so that not to expose what you don't want to expose.



来源:https://stackoverflow.com/questions/24607520/moq-only-one-method-in-a-class

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!