ASP.NET Core Web API - Testes Unitários com xUnit - I
  Neste artigo vamos continuar a criar casos de testes para uma API Asp.Net Core usando xUnit.


Continuando o artigo anterior vamos agora criar casos de teste para testar o serviço.
 

 


Testando o Serviço

 

Vamos iniciar escrevendo um caso de teste para o método Get em nosso serviço.

 

Em nossa API temos o serviço TarefaService que possui o seguinte código :

 

public class TarefaService : ITarefaService
{
    private readonly AppDbContext _context;
    public TarefaService(AppDbContext context)
    {
        _context = context;
    }

    public async Task<List<Tarefa>> GetTarefasAsync()
    {
        return await _context.Tarefas.ToListAsync();
    }

    public async Task CriaTarefaAsync(Tarefa novaTarefa)
    {
        _context.Tarefas.Add(novaTarefa);
        await _context.SaveChangesAsync();
    }
}

 

Nosso método Get TarefasAsync() retorna uma lista de objetos Tarefa e dependend do contexto definido por _context.

 

Vamos criar um arquivo de teste no projeto MinhaApi.Tests , na pasta Services, chamado TestTarefaService.cs e incluir o código abaixo :

 

public class TestTarefaService
{
    protected readonly AppDbContext _context;
    public TestTarefaService() : IDisposable
    {
        var options = new DbContextOptionsBuilder<AppDbContext>()
                          .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
                          .Options;
        _context = new AppDbContext(options);
        _context.Database.EnsureCreated();
    }
    [Fact]
    public async Task GetTarefasAsync_ReturnTarefaCollection()
    {
        /// Arrange
        _context.Tarefas.AddRange(MockData.TarefasMockData.GetTarefas());
        _context.SaveChanges();
        var sut = new TarefaService(_context);
        /// Act
        var result = await sut.GetTarefasAsync();
        /// Assert
        result.Should().HaveCount(TarefasMockData.GetTarefas().Count);
    }
    public void Dispose()
    {
        _context.Database.EnsureDeleted();
        _context.Dispose();
    }
}

 

Vamos entender o código:

 

A classe TestTarefaService implementa IDisposable

 

Em vez de mocar  o contexto 'AppDbContext', vamos criar o banco de dados na memória, para que nossos testes sejam mais fáceis e flexíveis. Aqui o construtor é invocado para cada execução do método de teste. Portanto, queremos criar um banco de dados em memória separado para cada método de teste unitário, portanto, temos que definir o nome exclusivo do banco de dados que obteremos usando o 'Guid'.;

 

Usamos o método EnsureCreated para garantir que o banco de dados existe. Se o banco não existir ele será criado. Se as tabelas não existirem o modelo das entidades será usado para criar as tabelas.;

 

No método de teste GetTarefasAsync_ReturnTarefaCollection estamos populando a tabela Tarefas do banco de dados em memória com alguns dados e criando o objeto para TarefaService;

 

Em Act estamos invocando o método de teste sut.GetTarefasAsync() e a seguir estamos verificando a saída conforme o que esperamos

 

Ao final o método 'Dispose' é executado na conclusão da execução do método do caso de teste. Aqui queremos destruir o banco de dados na memória para que cada caso de teste tenha seu próprio banco de dados na memória.

 

Executando o caso de teste no Test Explorer iremos obter:

 

 

Testando o Controller

Continuando vamos escrever um caso de teste para um método Action Post do nosso controlador TarefasController da API WebApi.

Abaixo temos os métodos do controlador TarefasController:

[Route("api/[controller]")]
[ApiController]
public class TarefasController : ControllerBase
{
    private readonly ITarefaService _tarefaService;
    public TarefasController(ITarefaService tarefaService)
    {
        _tarefaService = tarefaService;
    }
    [Route("tarefas")]
    [HttpGet]
    public async Task<IActionResult> GetTodasTarefasAsync()
    {
        var result = await _tarefaService.GetTarefasAsync();
        if (result.Count == 0)
        {
            return NoContent();
        }
        return Ok(result);
    }
    [HttpPost]
    [Route("novatarefa")]
    public async Task<IActionResult> NovaTarefaAsync(Tarefa novaTarefa)
    {
        await _tarefaService.CriaTarefaAsync(novaTarefa);
        return Ok();
    }
}

Vamos criar dados fictícios para usar no teste do método incluindo o método NovaTarefa abaixo na classe TarefasMockData

public static Tarefa NovaTarefa()
{
        return new Tarefa
        {
            Id = 0,
            Nome = "Completar leitura do artigo..",
            Concluida = false
        };
}

A seguir vamos criar o caso de teste para o método NovaTarefaAsync no controlador TestTarefasController :

    [Fact]
    public async Task NovaTarefaAsync_ShouldCall_ITarefaService_NovaTarefaAsync_UmaVez()
    {
        /// Arrange
        var tarefaService = new Mock<ITarefaService>();
        var novaTarefa = TarefasMockData.NovaTarefa();
        var sut = new TarefasController(tarefaService.Object);
        /// Act
        var result = await sut.NovaTarefaAsync(novaTarefa);
        /// Assert
        tarefaService.Verify(_ => _.CriaTarefaAsync(novaTarefa), Times.Exactly(1));
    }

Como nosso método 'TarefasController.NovaTarefaAsync()' não retorna nada, para realizar nossos testes aqui determinamos que o método 'TarefaService.CriaTarefaAsync()' seja executado exatamente uma vez.

Executando o caso no Test Explorer teremos :

Creio que você entendeu como realizar os testes de unidade e criar os casos de testes usando o xUnit.

Pegue o projeto aqui :  MinhaApi.zip (sem as referências)

"E a vós outros, que estáveis mortos pelas vossas transgressões e pela incircuncisão da vossa carne, vos deu vida juntamente com ele, perdoando todos os nossos delitos;"
Colossenses 2:13

Referências:


José Carlos Macoratti