Original title:
Moq: Mocking method method with
out parameterreturns empty array
The problem was not with the out parameter but with the complex type parameter albumFilters of complex type AlbumFilter. See my Answer for details.
I have Moq working for a method without an out parameter but when I try and Moq with an out parameter it returns an empty array.
The GetAllAlbums_ok_returnsdata_test() passes. The GetAllAlbumsPaged_test() fails. The call to the _inventoryService in the GetAllAlbumsPaged method in the AlbumApiController returns an empty array Album[].
I've looked at the Moq Quickstart section on using out arguments.
// out arguments
var outString = "ack";
// TryParse will return true, and the out argument will return "ack", lazy evaluated
mock.Setup(foo => foo.TryParse("ping", out outString)).Returns(true);
Test Class:
[Fact]
public void GetAllAlbums_ok_returnsdata_test() {
Mock<IInventoryService> mockInventoryService
= new Mock<IInventoryService>();
Album[] albums = { new Album { AlbumId = 1 },
new Album { AlbumId = 2 } };
mockInventoryService.Setup(obj => obj.GetAllAlbums()).Returns(albums);
AlbumApiController controller = new AlbumApiController(mockInventoryService.Object);
IHttpActionResult response = controller.GetAllAlbums();
var contentResult = response as OkNegotiatedContentResult<Album[]>;
Assert.NotNull(contentResult);
Assert.NotNull(contentResult.Content);
var data = contentResult.Content;
Assert.Equal(data, albums); }
[Fact]
public void GetAllAlbumsPaged_test() {
Mock<IInventoryService> mockInventoryService
= new Mock<IInventoryService>();
Album[] albums = new Album[20];
for (int i = 0; i < 20; i++) albums[i] = new Album { AlbumId = i + 1 };
var albumFilter = new AlbumFilter { AlbumNumber = "", Artist = "",
Title = "", Genre = 0, Price = 0, StockAmount = 0 };
var sortItems = new List<SortItem>();
int totalCount;
mockInventoryService.Setup(obj => obj.GetAllAlbumsPaged(out totalCount, albumFilter,
sortItems, 0, 4)).Returns(albums);
AlbumApiController controller = new AlbumApiController(mockInventoryService.Object);
IHttpActionResult response = controller.GetAllAlbumsPaged(Json.Encode(albumFilter),
Json.Encode(sortItems), 0, 4);
var contentResult = response as OkNegotiatedContentResult<object>;
Assert.NotNull(contentResult); }
AlbumApiController:
public class AlbumApiController : ApiController
{
private readonly IInventoryService _inventoryService;
public AlbumApiController(IInventoryService inventoryService)
{ _inventoryService = inventoryService; }
[HttpGet]
[Route("getallalbums")]
public IHttpActionResult GetAllAlbums() {
return GetHttpResponse(Request, () => {
var albums = _inventoryService.GetAllAlbums();
return Ok(albums); }); }
[HttpGet]
[Route("getallalbumspaged/{pageIndex}/{pageSize}")]
public IHttpActionResult GetAllAlbumsPaged(string filters, string sorts,
int pageIndex, int pageSize) {
var _filters = JsonConvert.DeserializeObject<AlbumFilter>(filters);
var _sorts = JsonConvert.DeserializeObject<List<SortItem>>(sorts);
return GetHttpResponse(Request, () => {
int totalCount;
var albums = _inventoryService.GetAllAlbumsPaged(out totalCount, _filters,
_sorts, pageIndex, pageSize);
var albums_Count = new { albums, totalCount };
return Ok(albums_Count); }); } }
Update:
I added this test method to the AlbumAPIController:
[HttpGet]
public IHttpActionResult GetTest(int intTest)
{
return GetHttpResponse(Request, () => {
int testInt;
var albums = _inventoryService.GetTest(out testInt, intTest);
return Ok(albums);
});
}
and this test to the test class:
[Fact]
public void GetTest_test() {
Mock<IInventoryService> mockInventoryService
= new Mock<IInventoryService>();
Album[] albums = new Album[20];
for (int i = 0; i < 20; i++) albums[i] = new Album { AlbumId = i + 1 };
int testInt = 15;
mockInventoryService.Setup(obj => obj.GetTest(out testInt, 5)).Returns(albums);
AlbumApiController controller = new AlbumApiController(mockInventoryService.Object);
IHttpActionResult response = controller.GetTest(5);
var contentResult = response as OkNegotiatedContentResult<Album[]>;
Assert.NotNull(contentResult);
Assert.NotNull(contentResult.Content);
var data = contentResult.Content;
Assert.Equal(data, albums); }
The test passed and the testInt was updated in the GetTest method so the problem doesn't seem to be with the 'out parameter`.
Per Diana's troubleshooting suggestion I added this to the GetAllAlbumsPaged method (right after the JsonConverts) to ensure the issue wasn't with the JSON.
_filters = new AlbumFilter { AlbumNumber = "", Artist = "",
Title = "", Genre = 0, Price = 0, StockAmount = 0 };
_sorts = new List<SortItem>();
The call to the _inventoryService.GetAllAlbumsPaged method still returns an empty array, Albums[].
albumFilterandsortItems. To confirm that, remove temporarily the out parameter from your method and check if the test still fails. In that case, check ifJsonConvert.DeserializeObject<AlbumFilter>(Json.Encode(albumFilter))is exactly equal to youralbumFiltervariable. Do the same forsortItems. I suspect that the mocked method is not being invoked because the parameter values don't match. - Diana