Как мне проверить, был ли вызван метод?

#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 ?