@PerseforeComplete

Как написать nUnit тест для ASP.NET контроллера, работающего с Task?

Вопросы в комментариях в тесте в конце.
Минимальный пример. Есть база. В базе есть модель. С моделью работаю через EF Core
class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Контроллер работает с моделью через сервис. Разумеется, в нём больше методов.
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();
}

Контроллер
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);
    }
}

В контроллерах, сервисах есть другие методы CRUD, они чуть сложнее (реализуют проверки), есть и другие модели. Тут пример нужен что бы минимально воспроизвести архитектуру и на примере теста для 1 метода я смогу понять как написать тесты на остальные методы.
Как написать nUnit тест на метод UsersController.Post?
Я использую Moq библиотеку и написал что-то вроде такого
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;
    }
}
  • Вопрос задан
  • 62 просмотра
Пригласить эксперта
Ответы на вопрос 2
vabka
@vabka Куратор тега C#
Токсичный шарпист
Зависит от того, какую библиотеку для моков вы используете, но, скорее всего:
1. в верхнем моке пишешь, с каким аргументом ожидается вызов метода этого сервиса
2. затем вызываешь метод контроллера с каким-то параметром (какой хочешь протестировать)
3. В конце делаешь ассерты, с помощью которых ты можешь убедиться, что у тебя всё сработало как надо.

В этом случае так:
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)); //Ассерт, что был вызван метод мока
Ответ написан
@AndromedaStar
.Net - monkey
Конечно, я уверен, меня тут побьют, но я обычно против юнит тестов контроллеров. Считаю это лишней потерей времени, так как по сути, я считаю, что юнит тесты - это тесты для бизнес логики. А её в контроллере не должно быть. В большинстве случаев тестируя контроллер вы будете тестировать корректную работу фреймворка, а это уже за вас сделали.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы