moq только один метод в классе

Я использую moq.файл DLL Когда я издеваюсь над классом (весь интерфейс IRepository), я использую этот код строки

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

но в этом случае я высмеиваю всю функцию в классе репозитория. Затем все методы в репозитории классов заменяются методами setup of Mock dll

Я хочу использовать все методы, определенные в репозитории классов (реальный класс) и макет только одной функции(SaveState)

Как я могу это сделать? Возможно ли это?

2 ответов


вы можете создать экземпляр реального репозитория, а затем использовать 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();
      }
   }

почему это не сработало. Однако основная проблема заключается в том, что вы не можете отлаживать внутри такого издевательского класса, даже если вы ставите точки останова там, где хотите. Это нехорошо. потому что ты можешь!--2-->действительно нужно что-то отладить.

Итак, я использовал гораздо более простое решение: объявите все методы, которые вы хотите высмеять как виртуальные. Затем наследуйте от этого класса и напишите однострочные макеты, чтобы вернуть то, что вы хотите, например:

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

вот и все. Затем вы можете использовать свои издевательские репозитории во время модульных тестов, и вы можете отлаживать все, что вам нужно. Вы даже можете оставить уровень защиты ниже публичного, чтобы не выставлять то, чего вы не делаете хочу разоблачить.