#c# #unit-testing #moq #autofixture
#c# #модульное тестирование #moq #автофиксация
Вопрос:
У меня есть ICreateService
класс, который зависит от ITicketApiAdapter
. Я попытался зарегистрировать макет ITicketAdaper, чтобы он вводился при создании анонимной службы создания.
Итак, в программе установки у меня есть этот регистр для адаптера ticket:
Fixture.Register(() =>
{
var ticketApiAdapter = new Mock<ITicketApiAdapter>();
ticketApiAdapter
.Setup( x => x.AddTicketComment(
It.IsAny<User>(),
It.IsAny<Customer>(),
It.IsAny<TicketComment>()))
.Returns(new SaveResult
{
Success = true,
Id = Fixture.CreateAnonymous<Guid>().ToString()
});
return ticketApiAdapter;
});
Fixture.Register(() => new CreateService(Fixture.CreateAnonymous<Mock<ITicketApiAdapter>>().Object));
Насколько я понимаю, это должно «заморозить» оба ICreateService
и Mock<ITicketApiAdapter>
, чтобы при запросе анонимного экземпляра это был тот, который я зарегистрировал.
У меня есть тест, который выглядит следующим образом:
[TestMethod]
public void CreateServiceCallsAddTicketComment()
{
var apiTicketAdapter = Fixture.CreateAnonymous<Mock<ITicketApiAdapter>>();
var createTicketRequest = Fixture.CreateAnonymous<CreateTicketComment>();
var createService = Fixture.CreateAnonymous<CreateService>();
var results = createService.CreateTicketComment(createTicketRequest);
apiTicketAdapter
.Verify(x => x.AddTicketComment(
It.IsAny<User>(),
It.IsAny<Customer>(),
It.IsAny<TicketComment>()),
Times.Once());
Assert.IsTrue(results.All(x => x.Success));
Assert.IsTrue(results.All(x => x.Errors.Count == 0));
}
Я ожидаю, что apiTicketAdapter будет тем, который я зарегистрировал, чтобы я мог проверить, что метод вызван. Если я выполняю переход, вызывается TicketApiAdapter, но Moq говорит, что этого не было.
Редактировать
Это ошибка, которую я получаю:
CreateServiceCallsAddTicketComment выдал исключение: Moq.Исключение MockException: ожидаемый вызов в макете один раз, но было 0 раз: x => x.AddTicketComment (It.IsAny(), Это.IsAny(), Это.IsAny())
Настроенные настройки: x => x.AddTicketComment (Ит.IsAny(), Это.IsAny(), Это.IsAny()), Раз.Никогда никаких вызовов не выполнялось.
Комментарии:
1. Какое точное сообщение о Moq оно показывает?
2. Пожалуйста, добавьте код метода AddTicketComment()
3. Это в первом блоке кода. Это просто макет, который возвращает хороший результат.
4. Я не понимаю, почему вы ожидаете, что метод AddTicketComment() вызывается в x.AddTicketComment() если вы вообще не вызываете его в этом методе, у вас нет реализации вашего CreateSerice, как я правильно понял. Как я понял, в классе CreateService у вас должен быть метод x.AddTicketComment() и этот метод должен вызывать AddTicketComment() ? можете ли вы показать реализацию CreateService?
5.
CreateService
ВызовыITicketApiAdapter.AddTicketComment()
внутриCreateService.AddTicketComment()
. Итак, когда я вызываюCreateService.AddTicketComment()
, я ожидаю, что он вызоветITicketApiAdapter.AddTicketComment()
Ответ №1:
Когда вы регистрируете блок кода, этот блок кода будет вызываться каждый раз, когда экземпляр Fixture разрешает запрошенный тип. Это означает, что он не заморожен. Если вы хотите что-то заморозить, часто проще использовать одну из перегрузок замораживания.
А еще лучше, поскольку вы, похоже, используете Moq, могу я предложить использовать расширение AutoMoq?
Это позволило бы вам переписать тест примерно так:
[TestMethod]
public void CreateServiceCallsAddTicketComment(new AutoMoqCustomization());
{
var fixture = new Fixture().Customize()
var apiTicketAdapter = fixture.Freeze<Mock<ITicketApiAdapter>>();
ticketApiAdapter
.Setup( x => x.AddTicketComment(
It.IsAny<User>(),
It.IsAny<Customer>(),
It.IsAny<TicketComment>()))
.Returns(new SaveResult
{
Success = true,
Id = Fixture.CreateAnonymous<Guid>().ToString()
});
var createTicketRequest = fixture.Freeze<CreateTicketComment>();
var createService = fixture.CreateAnonymous<CreateService>();
var results = createService.CreateTicketComment(createTicketRequest);
apiTicketAdapter
.Verify(x => x.AddTicketComment(
It.IsAny<User>(),
It.IsAny<Customer>(),
It.IsAny<TicketComment>()),
Times.Once());
Assert.IsTrue(results.All(x => x.Success));
Assert.IsTrue(results.All(x => x.Errors.Count == 0));
}
Предполагается, что CreateTicketRequest использует внедрение конструктора или свойства.
Комментарии:
1. Спасибо, Марк. Я читал ваш блог, но, похоже, не могу полностью разобраться с функциями автоматической фиксации / AutoMoq. Простой тест кажется достаточно простым, но мне не хватает полной настройки. Я хочу иметь возможность настроить
apiTicketAdapter
один раз, а затем протестировать все методы вCreateService
, вызывающие разные методы на адаптере. Если я освобожу ticket adapter в[TestSetup]
, могу ли я использовать Freeze в каждом[TestMehtod]
, чтобы получить тот же экземпляр для проверки того, что метод был вызван?2. Ответил на мой собственный вопрос, просто попробовав его 😉 кажется, он делает то, что я ожидал. Кстати, когда я пытаюсь перейти на ваш блог из результатов поиска Google, каждый раз происходит сбой Chrome.
3. Строка 6 вашего примера кода, должна ли она быть
apiTicketAdaptor
, а неticketApiAdaptor
?