Testando JsonResults que retornam tipos anônimos no Asp.Net MVC
Durante muito tempo eu usei reflection ou mesmo helpers que executam o contexto para testar JsonResults que retornam tipos anônimos.
Esses dias achei um truque bem legal que vou compartilhar aqui. Suponha a action abaixo:
1 2 3 4 5 6 |
public JsonResult GetSubstacoes(int skip, int take) { return Json(new { total = _rep.Query.Count(), subestacoes = _rep.Query.OrderBy(x => x.Nome).Skip(skip).Take(take) }); } |
ps: eu sei que eu poderia criar uma classe tipada e usar como retorno, mas estou fazendo proposital para demonstrar a ideia.
Usando a classe RouteValueDictionary, obtemos um dicionário de string/objeto já com todos os nossos objetos construídos. Este teste abaixo vai passar:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[Test] public void Paginacao_deve_retornar_subestacoes_e_count_total() { var items = Builder<Subestacao>.CreateListOfSize(10).Build(); _repMock.Setup(x => x.Query).Returns(items.AsQueryable); JsonResult result = _controller.GetSubstacoes(5, 5); var wrapper = new RouteValueDictionary(result.Data); //voodoo black magic var subestacoes = ((IEnumerable<Subestacao>) wrapper["subestacoes"]); Assert.AreEqual(10, wrapper["total"]); Assert.AreEqual(5, subestacoes.Count()); Assert.AreEqual("Nome5", subestacoes.First().Nome); } |
Bom TDD pra vocês.
EDIT:
O Juan Lopes comentou uma outra maneira de se testar json results que eu acho bem interessante. No comentário ele construiu uma representação DOM que implementa o método Equals. Não pesquisei como fazer isso no .net, mas podemos usar o mesmo serializador que o asp.net mvc usa e simplesmente comparar 2 strings, fazendo algo parecido:
1 2 3 4 5 6 7 8 9 10 11 12 |
[Test] public void Paginacao_deve_retornar_subestacoes_e_count_total_serializer() { var items = Builder<Subestacao>.CreateListOfSize(10).Build(); _mock.Setup(x => x.Query).Returns(items.AsQueryable); JsonResult json = _controller.GetSubstacoes(5, 5); var serializer = new JavaScriptSerializer(); string expected = "{\"total\":10,\"subestacoes\":[{\"Nome\":\"Nome5\"},{\"Nome\":\"Nome6\"},{\"Nome\":\"Nome7\"},{\"Nome\":\"Nome8\"},{\"Nome\":\"Nome9\"}]}"; string result = serializer.Serialize(json.Data); Assert.AreEqual(expected, result); } |
Já usei muito isso, mas dependendo da complexidade do objeto que queria retornar, ficava chato criar a string esperada na mão. Acabava usando o próprio serializador para pegar a string retornada, mas daí não dava pra escrever o teste antes.
O que gostei do primeiro método é que não vemos o json. Confiamos no serializador e checamos somente se estamos retornando as características corretas a serem consumidas. Por isso também que sempre que posso uso objetos tipados para as respostas.