将模拟方法的结果返回到另一个模拟方法

时间:2019-03-17 12:04:53

标签: c# unit-testing moq

我有一个具有以下实现的类:

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模拟方法在调用模拟的GetAllAsync方法之后进行一些逻辑处理?

1 个答案:

答案 0 :(得分:2)

首先,您显示的代码可能无法工作,因为您尝试设置的方法不是虚拟的。将要Setup的方法声明为virtual

第二,这是错误的:

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

通过此调用,您可以有效地设置GetListByMatchAsync来返回default(Task<IEnumerable<Hotel>>),即null。那显然不是您想要的。要么:

  • 使用.Returns(...)指定方法应返回的内容;或者,
  • 如果方法应仅返回基类中的实现将返回的内容,请使用.CallBase()。 (这可能是您所需要的。)