Вернуть результат смоделированного метода в другой смоделированный метод - PullRequest
1 голос
/ 17 марта 2019

У меня есть класс, который имеет следующую реализацию:

public sealed class HotelRepository : IHotelRepository
{
    private readonly string _dataSource;

    public HotelRepository(string dataSource) => _dataSource = dataSource;

    /// <inheritdoc />
    public async Task<IEnumerable<Hotel>> GetAllAsync() =>
        await Task.Run(() => JObject.Parse(File.ReadAllText(_dataSource))["hotels"].ToList().Select(x => x.ToObject<Hotel>()));

    /// <inheritdoc />
    public async Task<IEnumerable<Hotel>> GetListByMatchAsync(string name) =>
        await GetAllAsync().ContinueWith(x => x.Result.Where(y => y.Name.Contains(name, StringComparison.CurrentCultureIgnoreCase)));
}

Как видите, метод GetListByMatchAsync вызывает GetAllAsync, затем выполняет некоторую логику перед возвратом результата.

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

Вот модульный тест:

[TestCase("Test", "X")]
[TestCase("Hotel", "X")]
[TestCase("Name", "X")]
public async Task GetListByMatchAsync_GetHotelListByMatchingNameAsync_ReturnsFiveMatchingHotels(string name, string nonMatch)
{

    _hotelRepositoryMock = new Mock<IHotelRepository>();
    _hotelRepository = _hotelRepositoryMock.Object;

    // Set up sample data.
    var data = new List<Hotel>
    {
        new Hotel{Id = 1, Name = $"{name}", Description = "Description2", Location = "Location2", Rating = Rating.Two},
        new Hotel{Id = 2, Name = $"{name.ToUpper()}", Description = "Description1", Location = "Location1", Rating = Rating.Five},
        new Hotel{Id = 3, Name = $"{name.ToLower()}", Description = "Description2", Location = "Location2", Rating = Rating.Three},
        new Hotel{Id = 4, Name = $"{name} {nonMatch}", Description = "Description2", Location = "Location2", Rating = Rating.One},
        new Hotel{Id = 5, Name = nonMatch, Description = "Description2", Location = "Location2", Rating = Rating.One},
    };

    // Set up mock methods and ensure these method returns any sample data.
    _hotelRepositoryMock.Setup(x => x.GetListByMatchAsync(It.IsAny<string>()));
    _hotelRepositoryMock.Setup(x => x.GetAllAsync()).ReturnsAsync(data);


    var result = await _hotelRepository.GetListByMatchAsync(name);

    // Cast to list to make assertions.
    var hotels = result.ToList();

    Assert.That(hotels, Is.TypeOf<List<Hotel>>());
    Assert.That(hotels.Count, Is.EqualTo(4));
}

Как сделать так, чтобы этот тест работал так, чтобы метод GetListByMatchAsync mock выполнял некоторую логику после вызова метода GetAllAsync mocked?

1 Ответ

2 голосов
/ 20 марта 2019

Во-первых, код, который вы показали, не может работать, потому что методы, которые вы пытаетесь настроить, не являются виртуальными.Объявите методы, которые вы хотите Setup как virtual.

Во-вторых, это неправильно:

_hotelRepositoryMock.Setup(x => x.GetListByMatchAsync(It.IsAny<string>()));

С этим вызовом вы эффективно устанавливаетевверх GetListByMatchAsync для возврата default(Task<IEnumerable<Hotel>>), то есть null.Это явно не то, что вы хотите.Либо:

  • используйте .Returns(...), чтобы указать, что метод должен возвращать;или
  • используйте .CallBase(), если метод должен просто возвращать то, что вернет реализация в базовом классе.(Это, вероятно, то, что вам нужно.)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...