I'm learning how to write unit tests, please don't judge heavily. I have an API method below, written in C# for .NET 8.0, which I want to test. I use XUnit, Entity Framework Core 8, SQL Server 2019. Currently I'm rewriting it to separate the data layer, so I will not have to moq DB context.
[HttpGet("GetABunch")]
public async Task<ActionResult<TodoItem>> GetABunch()
{
string[] myAnimals = { "dog", "cat" };
var animals = await _context.TodoItems
.Where(i => myAnimals.Contains(i.Name))
.ToListAsync();
return Ok(animals);
}
My unit test is not working. I'm getting an error:
System.ArgumentException : Can not instantiate proxy of class: TodoApiDb.Models.TodoContext.
Could not find a parameterless constructor. (Parameter 'constructorArguments')
But before fighting this error, and creating context constructor without parameters, I believe my test is conceptually wrong, please help to fix it.
Here's my unit test:
[Fact]
public async Task GetABunch_ReturnsFilteredTodoItems()
{
// Arrange
var mockData = new List<TodoItem>
{
new TodoItem { Id = 1, Name = "dog" },
new TodoItem { Id = 2, Name = "cat" },
new TodoItem { Id = 3, Name = "bird" }
}.AsQueryable();
var mockSet = new Mock<DbSet<TodoItem>>();
mockSet.As<IQueryable<TodoItem>>().Setup(m => m.Provider).Returns(mockData.Provider);
mockSet.As<IQueryable<TodoItem>>().Setup(m => m.Expression).Returns(mockData.Expression);
mockSet.As<IQueryable<TodoItem>>().Setup(m => m.ElementType).Returns(mockData.ElementType);
mockSet.As<IQueryable<TodoItem>>().Setup(m => m.GetEnumerator()).Returns(mockData.GetEnumerator());
mockSet.As<IAsyncEnumerable<TodoItem>>().Setup(m => m.GetAsyncEnumerator(It.IsAny<CancellationToken>()))
.Returns(new TestAsyncEnumerator<TodoItem>(mockData.GetEnumerator()));
var mockContext = new Mock<TodoContext>();
//mockContext.Setup(c => c.TodoItems).Returns(mockSet.Object);
mockContext.Setup(c => c.Set<TodoItem>()).Returns(mockSet.Object);
var controller = new TodoItemsController(mockContext.Object);
// Act
var result = await controller.GetABunch();
// Assert
var actionResult = Assert.IsType<OkObjectResult>(result.Result);
var returnedItems = Assert.IsType<List<TodoItem>>(actionResult.Value);
Assert.Equal(2, returnedItems.Count);
Assert.Contains(returnedItems, i => i.Name == "dog");
Assert.Contains(returnedItems, i => i.Name == "cat");
}