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...");
}
вот и все. Затем вы можете использовать свои издевательские репозитории во время модульных тестов, и вы можете отлаживать все, что вам нужно. Вы даже можете оставить уровень защиты ниже публичного, чтобы не выставлять то, чего вы не делаете хочу разоблачить.