Поддельный асинхронный метод никогда не вызывается в Moq - PullRequest
0 голосов
/ 13 октября 2018

У меня есть интерфейс хранилища базы данных:

public interface IDbRepository
{
  Task<T> GetDataAsync<T>(Func<T, bool> filter = null) where T : class;
}

У меня есть следующее приспособление:

private List<Status> statusList = new List<Status> {
      new Status { Name="Status A"},
      new Status { Name="Status B"}
    };

var repositoryMock = new Mock<IDbRepository>();
Func<Status, bool> filter = It.IsAny<Func<Status, bool>>();
repositoryMock.Setup(repository => repository.GetDataAsync(filter))
  .ReturnsAsync(
  () =>
  {
    //NEVER CALLED
    if (filter == null)
      return statusList.FirstOrDefault();
    return statusList.FirstOrDefault(filter);
  });

Я использую следующий тест:

[Fact]
public async Task Repository_GetDataAsync_Filter()
{
  var repository = repositoryTestFixture.Ioc.Resolve<IDbRepository>();
  Func<Status, bool> filter = stat => stat.Name == "Status A";
  var res = await repository.GetDataAsync(filter);
  //await task1.ContinueWith(ctask => Assert.NotNull(ctask.Result));
  Assert.NotNull(res); //ALWAYS NULL!!!
}

Iпопытался отладить, и метод никогда не вызывался, поэтому я всегда получаю неудачный тест.

Согласно @Stephen Cleary, тест не требуется для вызова Wait() или Result, а старый официальный способ устарел с VisualStudio 2015, асинхронные тесты поддерживаются "из коробки".

Стивен Клири • https://stephencleary.com/ 11 месяцев назад (2017-11-03 12:22:06 pm) Как отмечалось вБольшое красное знамя вверху страницы, это решение было разработано для VS2010.VS2015 отлично работает с асинхронными тестами модулей из коробки.

Что я должен изменить?

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Я думаю, что проблема здесь из-за вашей filter локальной переменной.Создавая переменную, которая не является выражением, вы фактически выполняете вызов It.IsAny и возвращаете нуль.Как вы можете себе представить, null будет соответствовать только null функции, и поэтому вы не видите попадания ReturnsAsync.

Пожалуйста, попробуйте вставить эту переменную или изменить ее тип на Expression<Func<Status, bool>> и посмотрите, работает ли это так, как ожидалось.

Вы должны всегда иметь в виду, что настройка имитации выполняется с использованием выражений, поэтому обычно вызовы It.IsX никогда не выполняются сами по себе, просто анализируются и сравниваются какдерево выражений.

0 голосов
/ 13 октября 2018

Использование It.IsAny<>() является неточным.Он должен был использоваться непосредственно только в выражении Setup.Не в переменных.

Когда аргументы не совпадают, макет не вызывается.Следовательно, вы получаете ноль.

Доступ к переданному аргументу в пределах ReturnAsync делегата

var repositoryMock = new Mock<IDbRepository>();
repositoryMock
    .Setup(repository => repository.GetDataAsync(It.IsAny<Func<Status, bool>>()))
    .ReturnsAsync((Func<Status, bool> filter) => {//<-- grab passed argument here
        if (filter == null)
            return statusList.FirstOrDefault();
        return statusList.FirstOrDefault(filter);
    });
...