P
P
PerseforeComplete2021-09-09 21:17:51
ASP.NET
PerseforeComplete, 2021-09-09 21:17:51

How to write an nUnit test for an ASP.NET controller that works with a Task?

Questions in the comments at the end of the test.
Minimal example. There is a base. The database has a model. Working with the model through EF Core

class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

The controller works with the model through a service. Of course, it has more methods.
public interface IUserService
{
    public void Add(User value); 
}

public class UserService : IUserService
{
    private readonly IApplicationContext context;
    public UserService(IApplicationContext context) => this.context = context;

    public void Add([FromBody] User value)
    {
        context.Users.Add(value);
        context.SaveChanges();
    }
}

public interface IApplicationContext
{
    public DbSet<User> Users { get; set; }
    public void SaveChanges();
}

Controller
public class UsersController : ControllerBase
{
    private readonly IUserService userService;
    public UsersController(IUserService service) => userService = service;

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] User value)
    {
        userService.Add(value);
        return Ok(value);
    }
}

There are other CRUD methods in controllers, services, they are a little more complicated (they implement checks), there are other models. Here an example is needed to minimally reproduce the architecture and using the example of a test for 1 method, I can understand how to write tests for other methods.
How to write an nUnit test for the UsersController.Post method?
I am using Moq library and wrote something like this
public class UsersControllerTests
{
    [Test]
    public void AddTest()
    {
        var mock = new Mock<IUserService>();
        mock.Setup(service=>service.Add(new User()); // что писать внутри Add? 
        var controller = new UsersController(mock.Object);
 
        var result = controller.Add(new User()); // Что писать внутри этого Add? Как он коррелирует с предыдущим Add?
 
        // Что вообще писать на этапе Assert?
    }
    private List<User> GetTestUsers()
    {
        var users = new List<User>
        {
            new User { Id=1, Name="Tom" },
            new User { Id=2, Name="Alice" },
            new User { Id=3, Name="Sam" },
            new User { Id=4, Name="Kate" }
        };
        return users;
    }
}

Answer the question

In order to leave comments, you need to log in

2 answer(s)
V
Vasily Bannikov, 2021-09-09
@vabka

Depends on what library for mocks you use, but most likely:
1. in the top mock you write with what argument the method of this service is expected to be called
2. then you call the controller method with some parameter (what you want to test)
3. In At the end, you make assertions, with the help of which you can make sure that everything worked out for you as it should.
In this case like this:

var user = new User();

var mock = new Mock<IUserService>();
mock.Setup(service=>service.Add(user)); 
var controller = new UsersController(mock.Object);

var result = (OkObjectResult) await controller.Add(user); // await не забываем

Assert.Equals(user, result.Value); // Ассерт, что контроллер вернул что ожидали
mock.Verify(x=>x.Add(user)); //Ассерт, что был вызван метод мока

A
AndromedaStar, 2021-09-10
@AndromedaStar

Of course, I'm sure I'll get beaten here, but I'm usually against unit testing controllers. I think this is a waste of time, because in fact, I believe that unit tests are tests for business logic. And it should not be in the controller. In most cases, when testing a controller, you will be testing the correct operation of the framework, and this has already been done for you.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question