[英]Return the result of a mocked method to another mocked method
I've got a class that has the following implementation: 我有一个具有以下实现的类:
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)));
}
As you can see, the GetListByMatchAsync
method calls GetAllAsync
, then does some logic before returning the result. 如您所见,
GetListByMatchAsync
方法调用GetAllAsync
,然后在返回结果之前执行一些逻辑。
When I tried to mock this repository for unit testing, I'm struggling to get a result out of GetListByMatchAsync
as it always fails as a null reference exception. 当我尝试模拟此存储库以进行单元测试时,我正在努力从
GetListByMatchAsync
获取结果,因为它始终会作为空引用异常而失败。
Here's the unit test: 这是单元测试:
[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));
}
How can I make this test work such that the GetListByMatchAsync
mock method does some logic after calling the mocked GetAllAsync
method? 我怎样才能让这个测试工作,使得
GetListByMatchAsync
模拟方法做了一些逻辑调用嘲笑后GetAllAsync
方法?
First, the code that you have shown cannot possibly work because the methods that you are trying to set up are not virtual. 首先,您显示的代码可能无法正常工作,因为您尝试设置的方法不是虚拟的。 Declare the methods you want to
Setup
as virtual
. 声明要
Setup
为virtual
。
Second, this is wrong: 其次,这是错误的:
_hotelRepositoryMock.Setup(x => x.GetListByMatchAsync(It.IsAny<string>()));
With this call, you're effectively setting up GetListByMatchAsync
to return default(Task<IEnumerable<Hotel>>)
, ie null
. 通过此调用,您可以有效地设置
GetListByMatchAsync
以返回default(Task<IEnumerable<Hotel>>)
,即null
。 That's obviously not what you want. 那显然不是您想要的。 Either:
或者:
.Returns(...)
to specify what the method should return; .Returns(...)
指定方法应返回的内容; or, .CallBase()
if the method should simply return whatever the implementation in the base class would return. .CallBase()
。 (This is likely what you need.)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.