FakeItEasy ControllerTest Вызовы HttpGet - PullRequest
0 голосов
/ 07 мая 2020

Я хочу начать использовать FakeItEasy для тестирования запросов. Тесты, которые я хочу написать, должны проверять, возвращаются ли объекты при вызовах HttpGet (получить все и получить по идентификатору)

Контроллер:

public class ToDoController : ControllerBase
  {
    private readonly IMediator _mediator;

    public ToDoController(IMediator mediator) =>
    _mediator = mediator;

    [HttpGet]
    [Produces("application/json")]
    [ProducesResponseType(typeof(IEnumerable<ToDoItem>), (int)HttpStatusCode.OK)]
    public async Task<ActionResult<IEnumerable<ToDoItem>>> Get()
    {
        var result = await _mediator.Send(new ToDoItemsQuery(new 
                         AllToDoItems())).ConfigureAwait(false);

        if (result != null && result.Any())
        {
            return result.ToList();
        }

        throw new InvalidOperationException("TODO: error handling");
    }

    [HttpGet]
    [Route("{id}")]
    [Produces("application/json")]
    [ProducesResponseType(typeof(ToDoItem), (int)HttpStatusCode.OK)]
    public async Task<ActionResult<ToDoItem>> GetById(int itemId)
    {
      var result = await _mediator
        .Send(new ToDoItemsQuery(new ToDoItemById(itemId)))
        .ConfigureAwait(false);

      if (result != null && result.Any())
      {
        return result.FirstOrDefault(); 
      }

      throw new InvalidOperationException("TODO: error handling");
    }
  }
}

TestClass:

public class ToDoItemControllerTests : ControllerTestBase
{
  private IMediator _mediator;

  private ToDoController _sut;

  public ToDoItemControllerTests()
  {
    _mediator = A.Fake<IMediator>();
    _sut = new ToDoController(_mediator);
  }

  [TestMethod]
  public async Task GetAllItemsAsync_SuccessTest()
  {
    A.CallTo(() => _mediator.Send(A<AllToDoItems>._, 
           A<CancellationToken>._)).Returns(A.CollectionOfFake<ToDoItem>(10));
    var result = await _sut.Get();

    Assert.IsNotNull(result);
    A.CallTo(() => _mediator).MustHaveHappened();
  }

  [TestMethod]
  public async Task GetItemByIdAsync_SuccessTest()
  {
    // Arrange
    int itemId = 2;
    var commandResult =
      new List<ToDoItem>
      {
        new ToDoItem
        {
          Id = itemId        
        };
      }

    A.CallTo(() => MediatR.Send(A<ToDoItemById>._, A<CancellationToken>._)).Returns(commandResult);

    // Act
    var result = await _sut.GetById(itemId);

    // Assert
    Assert.IsNotNull(result);
    A.CallTo(() => MediatR.Send(A<ToDoItemById>._, A<CancellationToken>._)).MustHaveHappened();
  }
}

Итак, в первом тесте я настроил A.CallTo интерфейса IMediatR, чтобы он возвращал 10 ToDoItems. Во время отладки я вижу, что _sut.Get () входит в контроллер, вводя правильный метод / вызов API. _Mediator.Send () в контроллере возвращает Fake IEnumerable (не 10 элементов, которые я установил в первом Call.To в методе тестирования, а перечисление, которое не дает результатов).

Из-за результата .Any () имеет значение false, контроллер выдает исключение InvalidOperationException, и я не могу даже подтвердить результат. IsNotNull ()

Второй тест, который я хочу проверить, если при вызове API возвращается 1 элемент. Я установил (а) itemId типа int для параметра, (b) фиктивный (?) Список с 1 элементом из настройки с itemId и (c) вызов mediatR должен вернуть фиктивный список из (b )

Я выполняю вызов из теста, при отладке я вижу, что вызов await _mediator.Sent () возвращает Fake Ienumerable of ToDoItem, результат не равен нулю, но поскольку result.Any () является ложным, элемент не возвращается, и я получаю еще одно исключение InvalidOperationException

Мне кажется, что мне что-то не хватает в настройке тестов .. Поддельный интерфейс базы данных? Я не хочу рисковать своим контроллером и делать if менее ограничивающим, просто чтобы мой тест прошел

EDIT: даже если я изменю условие if на удаление условия Any, и я вижу, что тест входит в контроллер , возвращая результат «First or Default», тест не проходит при вызове, который должен был произойти. Ожидалось найти его один или несколько раз, но никаких обращений к поддельному объекту не производилось. Я действительно не понимаю, я действительно вижу, как он звонит?!

Я просмотрел GitHub, чтобы найти примеры, но ближе всего я нашел Entities с методами, причем эти методы определены в интерфейсе. Здесь дело обстоит не так.

Поскольку официальная документация не делает меня мудрее, я обращаюсь к SO <3 Заранее спасибо! </p>

1 Ответ

2 голосов
/ 08 мая 2020

В первом тесте вы настраиваете вызов Send с аргументом типа AllToDoItems. Но в контроллере вы фактически вызываете Send с помощью TodoItemsQuery. Таким образом, вызов не совпадает, и применяется поведение по умолчанию (ненастроенное), которое возвращает поддельный IEnumerable. Вам нужно настроить вызов следующим образом:

A.CallTo(() => _mediator.Send(A<TodoItemsQuery>._, 
           A<CancellationToken>._)).Returns(A.CollectionOfFake<ToDoItem>(10));

Во втором тесте проблема такая же, с ToDoItemById вместо AllToDoItems

...