将模拟对象返回到测试方法的正确方法

时间:2017-01-09 12:06:16

标签: c# unit-testing moq

我正在为我的方法编写单元测试:

[HttpGet("sani")]
[RequireHttps]
public async Task<IActionResult> GetSuppliersAsync(double latitude, double longitude)
{
    if (ModelState.IsValid)
    {
        var supplierList = new List<Supplier>();
        var externalSupplierList = new List<ExternalSupplier>();
        try
        {
            await _supplierRepository.GetSuppliersAsync(supplierList);
            await _supplierRepository.GetExternalSupplierAsync(externalSupplierList);
        }
        catch (Exception)
        {
            return BadRequest("db");
        }

        var coll = new Dictionary<dynamic, double>();

        AddToCollectionInParallel(supplierList, latitude, longitude, coll);

        coll.OrderBy(x => x.Value);
        AddExternalToCollectionInParallel(externalSupplierList, latitude, longitude, coll);

        return new OkObjectResult(coll.Keys);
    }
    return BadRequest("model");
}

如您所见,我传递给 GetSuppliersAsync() GetExternalSuppliers()列表,这些列表应填写在那里。我没有返回列表(所以它会像:var supplierList = _supplierRepository.GetSuppliersAsync();),因为传递对象(列表)并将其填入方法然后返回列表会更快。 所以现在我想写一个单元测试。我正在使用Xunit进行单元测试。我的测试方法:

[Xunit.Fact]
public async Task GetSuppliersAsyncDbTest()
{
    var list = new List<Supplier>();
    list.Add(new Supplier { SupplierId = "ertre", SupplierName = "test" });
    var extList = new List<ExternalSupplier>();
    extList.Add(new Models.ExternalSupplier { Id = 4});
    _mockRepo.Setup(repo => repo.GetSuppliersAsync(list)).Returns(Task.FromResult(list));
    _mockRepo.Setup(repo => repo.GetExternalSuppliersAsync(extList)).Returns(Task.FromResult(extList));
    var controller = new SupplierController(_mockRepo.Object);
    var result = await controller.GetSuppliersAsync(0.0, 0.0);
    var viewResult = Xunit.Assert.IsType<OkObjectResult>(result);
    Xunit.Assert.Equal(200, viewResult.StatusCode);
}

我的问题是,在单元测试期间,当我调用行await _supplierRepository.GetSuppliersAsync(supplierList);时,它返回空列表,尽管我已经嘲笑返回列表中有一个项目。但是,当我更改为var supplierList = _supplierRepository.GetSuppliersAsync();时,它会按预期返回一个项目。 任何想法如何解决它,或者我应该只重写方法将值返回为List?

2 个答案:

答案 0 :(得分:1)

您使用供应商列表的具体实例模拟了存储库的GetSuppliersAsync()。但是,在您的控制器方法中,将使用另一个实例,并且不会返回您的存根值。要解决此问题,您应该在模拟设置期间使用参数匹配器:

_mockRepo.Setup(repo => repo.GetSuppliersAsync(It.IsAny<List<Supplier>>()))
.Returns(Task.FromResult(list));

您的存储库GetSuppliersAsync()如何工作?它会改变参数中传递的列表还是返回供应商列表?如果是第二种情况,那么您应该分配从存储库返回的列表:

supplierList = await _supplierRepository.GetSuppliersAsync(supplierList);
externalSupplierList = await _supplierRepository.GetExternalSupplierAsync(externalSupplierList);

答案 1 :(得分:1)

你可以两种方式做到:

按参数返回:

 var supplierList = new List<Supplier>();
 await _supplierRepository.GetSuppliersAsync(supplierList);

使用

_mockRepo.Setup(repo => repo.GetSuppliersAsync(It.IsAny<List<Supplier>>()))
.Returns((List<Supplier> x) => {x.AddRange(list); return Task.Delay(0); });

或重构您的代码以返回列表:

 var supplierList =  await _supplierRepository.GetSuppliersAsync();

使用

_mockRepo.Setup(repo => repo.GetSuppliersAsync())
.Returns(Task.FromResult(list));

返回列表时没有性能差异,所以我建议重构代码。更清楚的是这是怎么回事。