当前位置: 首页 > 知识库问答 >
问题:

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

丁翊歌
2023-03-14

我有一个类,它有以下实现:

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个答案

松和璧
2023-03-14

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

第二,这是错误的:

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

通过此调用,您可以有效地将GetListByMatchAsync设置为返回Default(Task >) ,即Null。那显然不是你想要的。其中之一:

  • 使用.returns(...)指定方法应返回的内容;或,
  • 如果方法应该简单地返回基类中的实现将返回的任何内容,请使用.callBase()。(这可能是您需要的。)
 类似资料:
  • 我想mock接受对象参数的方法。此对象参数是从动态创建的。不会返回预期的结果,尽管这两个对象具有相同的数据,但只是不同的哈希代码。 有没有什么方法来模拟方法,使它能够以预期的结果响应?

  • 如何模拟返回已强制转换的模拟对象的方法。 试验方法。

  • 我调用了一个方法,它连接到另一个服务器,每次调用它,它都返回不同的数据。 我正在为调用该方法的类编写一个单元测试。我已经嘲笑了那个类,我希望它返回存根结果。它实际上使用工作,但是它每次都返回相同的数据。我希望它返回不同的数据,我希望能够指定它应该是什么。 我试着使用“doReturn-when”,它可以工作,但我无法让它返回不同的结果。我不知道怎么做。 我还尝试使用“when-thenReturn

  • 上面还有第二个问题。当我在Expects块中定义mock类时(如上),似乎只调用了构造函数,而不是,因此没有正确初始化对象。我通过将它移到方法中并在那里实例化该类来解决这个问题。看起来是这样的: 因此,这似乎得到了要调用的正确构造函数,但似乎还在调用。有什么见解吗?

  • 我有一个方法,我需要写单元测试用例。该方法返回类型。