Vinicius Quaiato

{tecnologia, conceitos, negócios, idéias, práticas, .NET, ruby, osx, ios e algo mais}

ASP.NET MVC: Testando controllers parte III


Fala galera, neste terceiro post sobre ASP.NET MVC e testes(post I e post II) vou mostrar como testar a action de um controller que realiza upload de arquivos.# Testar um controller que realiza upload de arquivos Este não é o teste mais simples, mas também não é complexo. A particularidade aqui é que estou utilizando o Moq, e com ele não consigo dar "bypass" nas propriedades que eu não quero mockar, ou seja, preciso mockar toda a cadeia da chamada (se vocês tiverem uma forma mais simples, é só mandar).

Configurando arquivo Resources

Vamos lá, antes de codificar, eu adiciono um arquivo de recursos no projeto de testes e adiciono uma foto como resource:

O código de testes

public void Deve_Salvar_Uma_Imagem_Que_Foi_Postada(){    //Arrange
var controllerFotos = new ControllerFotos();
var encoding = new UTF8Encoding();
var memoryStream = new MemoryStream();
    ArquivosPostados.ImagemPostada.Save(memoryStream, ImageFormat.Jpeg);
    postedFile = new Mock<httppostedfilebase>();
    postedFile.Setup(p => p.InputStream).Returns(memoryStream);
var files = new Mock<httpfilecollectionbase>();
    files.Setup(f => f[0]).Returns(postedFile.Object);
var request = new Mock<httprequestbase>();
    request.Setup(r => r.Files).Returns(files.Object);
var context = new Mock<httpcontextbase>();
    context.Setup(c => c.Request).Returns(request.Object);
    controllerContext = new ControllerContext(context.Object, new RouteData(), controllerFotos);
    controllerFotos.ControllerContext = controllerContext;
    //Act    controllerFotos.Upload();
    //Assert    postedFile.Verify(p => p.SaveAs(It.IsAny<string>()), Times.Once());
    }
</string></httpcontextbase></httprequestbase></httpfilecollectionbase></httppostedfilebase>

Explicando o teste

O teste em si é bastante simples.Nas linhas 6, 7 e 8 o que fazemos é pegar a imagem do arquivo de resources e jogamos para um MemoryStream. Fazemos isso pois é desta forma que o PostedFile trabalha, com um Stream.ArquivosPostados é o nome do meu arquivo de resource, e ImagemPostada é o nome da imagem que adicionei ao arquivo.Nas linhas 10 e 11 criamos um mock para HttpPostedFileBase, que é o tipo a ser retornado pela lista de PostedFiles no nosso controller. E configuramos ele para retornar nossa imagem que está no memory stream.Nas linhas 13 e 14 configuramos a coleção de arquivos mockando o HttpFileCollectionBase. Dizemos que quando for acessado o índice zero desta coleção deve retornar nosso posted file mockado.Nas linhas 16 e 17 criamos o mock do HttpRequestBase, desta forma quando for solicitado a coleção de Files retornaremos nossa lista mockada.Nas linhas 19 e 20 fazemos o mock do HttpContextBase, assim quando solicitarmos o Request retornaremos nosso request mockado.Para finalizar, nas linhas 22 e 23 criamos um ControllerContext usando nosso HttpContext mockado, e então colocamos este contexto no nosso controller.Isso tudo serve para que tenhamos controle total sobre todos os arquivos passados para nosso controller, sem haver nenhuma necessidade do upload manual, tornando assim o teste realmente automatizado.Na linha 26 fazemos a chamada para a action, nesse caso chamada Upload.Na linha 29 fazemos a verificação para saber se nossa action realmente salvou o arquivo que foi enviado.Abaixo temos o código do nosso controller:

public ViewResult Upload(){
if(Request.Files[0] != null)    {        Request.Files[0].SaveAs(string.Empty);
return View("UploadSucesso");
    }
return View();
    }

Considerações

O código de testes pode parecer longo, e o código do controller relativamente simples. Mas é claro que este código está bem resumido. O controller provavelmente faz mais coisas do que simplesmente salvar a imagem em disco. Talvez hajam validações quanto ao nome, formato, tamanho do arquivo. Talvez exista uma rotina para realizar crop, resize, rename da imagem. Tudo isso deve ser testado, e sinceramente, esse código é bastante simples e rápido de ser escrito, e não custa nada criar alguns testes como este. Sendo assim, acho que há benefício em manter este teste na sua suíte e no seu projeto.Eu consegui não precisar mockar todos estes objetos utilizando o framework de mock da Telerik - JustMock. Mas como é um produto pago, preferi não basear meu post nele.Com Rhino e Moq eu não consegui o mesmo resultado. Então se vocês tiverem sugestões e conhecimento de como não mockar todos estes objetos, é só enviar e eu divulgo.É isso galera, espero que este tipo de testes também lhes seja útil e ajude a criar aplicações ainda mais robustas com ASP.NET MVC.

Abraços, Vinicius Quaiato.

Voltar

Fork me on GitHub