Neste artigo vou explicar como programar testes unitários para controllers do ASP.NET Web API 2 que retornam seus dados em uma resposta HTTP do tipo IHttpActionResult.
O projeto base para este artigo pode ser encontrado no post que explica testes unitários para controllers do ASP.NET Web API 2 que retornam seus dados em uma resposta HTTP do tipo HttpResponseMessage.
Aqui no blog também tem outro post que explica a diferença entre o IHttpActionResult e o HttpResponseMessage.
Assim como no outro artigo, devemos iniciar adicionando um projeto de testes na nossa solução do Visual Studio. Para adicioná-lo basta clicar com o botão direito do mouse na sua solution e seguir os passos Add > New Project > Test > Unit Test Project.
Um ponto importante é se lembrar de adicionar o pacote Microsft.AspNet.WebApi.Core para que seja possível criar os objetos de controller na nossa classe de testes.
Acessando o projeto exemplo no GitHub vocês podem conferir que o método Initialize() faz as inicialização do repositório já com alguns dados de exemplo.
O primeiro teste irá validar o comportamento de listar todos os registros do nosso repositório através do método Get() da controller.
Nele iremos instanciar o nosso controller e passar como parâmetro um objeto de repositório com os nossos dados de exemplo. Em seguida iremos chamar o método Get() e o seu retorno será armazenado na variável result.
[TestMethod]
public void ShouldGetAllCars()
{
var controller = new CarController(_repository);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
var result = controller.Get() as OkNegotiatedContentResult<IEnumerable<Car>>;
Assert.IsNotNull(result);
Assert.IsNotNull(result.Content);
Assert.AreEqual(3, result.Content.Count());
}
O resultado do tipo IHttpActionResult, para ser devidamente testado, precisa ser armazenado numa variável do tipo OkNegotiatedContentResult. Esse tipo de objeto corresponde ao conteúdo do resultado sendo considerado como uma reposta HTTP do tipo Ok.
Mais tipos de objetos podem ser encontrados no namespace System.Web.Http.Results. Por exemplo, uma resposta HTTP do tipo Created pode ser testada usando o CreatedNegotiatedResult, ou uma resposta HTTP do tipo NotFound pode ser testada usando o NotFoundResult. Na documentação oficial do ASP.NET Web API 2 temos uma explicação mais detalhada sobre esses objetos.
Para validar o resultado iremos usar o Assert.IsNotNull que verifica se a resposta retornada não é vazia. Em seguida validamos que o conteúdo dessa reposta também não é vazio. A última validação usa o Assert.AreEqual para verificar se os registros retornados possuem a mesma quantidade que foi configurada ao criar o objeto de repositório, neste caso, se o result.Content.Count() é igual a 3.
Outro tipo teste interessante para se fazer é validar se o tipo de reposta representa um código HTTP de erro como NotFound ou BadRequest. No nosso projeto de teste temos um método de ShouldReturnNotFound() para validar que um GET retornou o código de status HTTP correspondente a um NotFound.
[TestMethod]
public void ShouldReturnNotFound()
{
var controller = new CarController(_repository);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
var result = controller.Get("Ferrari F7");
Assert.IsInstanceOfType(result, typeof(NotFoundResult));
}
Os demais métodos de teste para cada ação do nosso controller seguem a mesma estrutura dos exemplos mostrados. A diferença está no que está sendo validado. Pode ser um campo do objeto, pode ser a quantidade de registros retornados, ou até mesmo se o objeto é nulo. Acompanhe abaixo a classe de testes com todos os métodos.
[TestMethod]
namespace LuizPauloPradoBlog.WebApi.Tests
{
[TestClass]
public class CarControllerTest
{
private ICarRepository _repository;
[TestInitialize]
public void Initialize()
{
var carSamples = new List<Car>();
carSamples.Add(new Car() { Name = "Fiesta", Model = "Fiesta SE", YearOfManufacture = 2015 });
carSamples.Add(new Car() { Name = "Golf", Model = "Golf Sport", YearOfManufacture = 2015 });
carSamples.Add(new Car() { Name = "Civic", Model = "Civic S", YearOfManufacture = 2016 });
_repository = new CarRepository(carSamples);
}
[TestMethod]
public void ShouldGetAllCars()
{
var controller = new CarController(_repository);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
var result = controller.Get() as OkNegotiatedContentResult<IEnumerable<Car>>;
Assert.IsNotNull(result);
Assert.IsNotNull(result.Content);
Assert.AreEqual(3, result.Content.Count());
}
[TestMethod]
public void ShouldGetCar()
{
var controller = new CarController(_repository);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
var result = controller.Get("Fiesta SE") as OkNegotiatedContentResult<Car>;
Assert.IsNotNull(result);
Assert.IsNotNull(result.Content);
Assert.AreEqual(result.Content.Model, "Fiesta SE");
}
[TestMethod]
public void ShouldPostCar()
{
var controller = new CarController(_repository);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
var newCar = new Car() { Name = "IX 35", Model = "IX 35 Special", YearOfManufacture = 2016 };
var result = controller.Post(newCar) as CreatedNegotiatedContentResult<Car>;
Assert.IsNotNull(result);
Assert.IsNotNull(result.Content);
Assert.AreEqual(result.Content.Name, newCar.Name);
Assert.AreEqual(result.Content.Model, newCar.Model);
Assert.AreEqual(result.Content.YearOfManufacture, newCar.YearOfManufacture);
}
[TestMethod]
public void ShouldReturnNotFound()
{
var controller = new CarController(_repository);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
var result = controller.Get("Ferrari F7");
Assert.IsInstanceOfType(result, typeof(NotFoundResult));
}
}
}
O último passo é conferir se está tudo funcionando corretamente e executar todos os testes do projeto.

O projeto completo de exemplo pode ser encontrado no meu GitHub.
Se quiserem conhecer mais sobre mim, basta ir aqui no blog no menu quem sou e conferir também o meu LinkedIn.
Se ficou alguma dúvida, ou se algo não funcionou, deixa um comentário aqui no blog que esclareço as dúvidas.
Parabéns pelo post Luiz. Objetivo e útil !
CurtirCurtir
Obrigado! Que bom que gostou! 🙂
CurtirCurtir