Reputation: 853
I am writing unit test for my method:
[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");
}
As you can see, I pass to GetSuppliersAsync() and GetExternalSuppliers() lists, that should be filled there. I do not return lists (so it would be something like: var supplierList = _supplierRepository.GetSuppliersAsync();
) because it will be faster to pass object (list) and fill it in method then return list.
So now I want to write an unit test. I am using Xunit for unit tests. My test method:
[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);
}
My problem is that during unit test, when I call line await _supplierRepository.GetSuppliersAsync(supplierList);
it returns empty list, in despite of I've mocked to return list with one item inside. But when I change to var supplierList = _supplierRepository.GetSuppliersAsync();
it returns one item, as expected.
Any ideas how can fix it, or I should just rewrite method to return values as List?
Upvotes: 0
Views: 262
Reputation: 31312
You mocked repository's GetSuppliersAsync()
with concrete instance of Supplier list. However in your controller method another instance is used and your stub value is not returned. To fix this you should use argument matcher during mock setup:
_mockRepo.Setup(repo => repo.GetSuppliersAsync(It.IsAny<List<Supplier>>()))
.Returns(Task.FromResult(list));
And how does your repository GetSuppliersAsync() works? Does it alter list passed in parameter or it returns suppliers list? If it's the second case then you should assign the list returned from repository:
supplierList = await _supplierRepository.GetSuppliersAsync(supplierList);
externalSupplierList = await _supplierRepository.GetExternalSupplierAsync(externalSupplierList);
Upvotes: 1
Reputation: 12629
You can do it both ways:
to return by parameter:
var supplierList = new List<Supplier>();
await _supplierRepository.GetSuppliersAsync(supplierList);
use
_mockRepo.Setup(repo => repo.GetSuppliersAsync(It.IsAny<List<Supplier>>()))
.Returns((List<Supplier> x) => {x.AddRange(list); return Task.Delay(0); });
or refactor your code to return lists:
var supplierList = await _supplierRepository.GetSuppliersAsync();
use
_mockRepo.Setup(repo => repo.GetSuppliersAsync())
.Returns(Task.FromResult(list));
There is no performance difference to speak of while returning list so I would advise to refactor your code. It is more clear what is going on that way.
Upvotes: 1