17 Apr
Aplicações para a Internet que se comunicam umas com as outras é algo mais do que comum. Ou sua aplicação consome algo que outra produz ou ela produz algo para outra consumir.
É bem fácil testar o que sua aplicação produz. Basta subir um servidor local, fazer uma requisição para o endereço correspondente e processar o resultado. Mas, por outro lado, como testar que sua aplicação consome o que outra produz adequadamente?
É claro que não vamos querer depender da aplicação remota de verdade. Queremos deixar os testes automatizados o mais isolados possível dos recursos externos. Então vamos, provavelmente, querer que o objeto responsável por fazer as requisições para fora não as faça de verdade e que devolva dados semelhantes aos da aplicação real.
Um jeito de fazer isso seria “embrulhar” a comunicação com a Internet numa classe nossa e, nos testes, mockar essa classe e passar essa classe mockada para as classes (ou os métodos) que precisam dela. É possível fazer isso em qualquer linguagem que suporte orientação a objetos.
Em Ruby ainda temos uma outra possibilidade. Como as classes são abertas, podemos re-escrever os métodos da classe Net::HTTP, por exemplo. Assim, não precisamos criar um embrulho; podemos utilizar sempre a classe do sistema.
Pois também não precisamos fazer isso na mão. A gem FakeWeb permite mockar requisições para determinadas URIs com um código bastante sucinto. Por exemplo, se você quiser que seu programa receba “olá mundo” quando fizer uma requisição do tipo GET para a URI http://foo.com/bar, basta escrever antes do código que executa a requisição:
FakeWeb.register_uri(:get, "http://foo.com/bar", :body => "olá mundo")
Em Java também é possível fazer algo parecido com um pouco de magia negra, desde que controlemos a criação do objeto responsável pela requisição. Mas, a meu ver, a primeira abordagem resulta num código mais desacoplado. Qual a sua opinião?
Posts Relacionados:
Acompanhe-nos por
RSS, por Email ou via Twitter.
Veja como ter um desconto no Dreamhost: um excelente servidor web.
Email This Post
4 Responses for "Uma gem para testar aplicações que se comunicam com a Internet"
Luiz,
Eu ate concordo em que alguns casos a FakeWeb faz sentindo, principalmente com serviços de terceiros e api mais estáveis, mas ao longo do tempo a cada novo projeto eu tenho mais medo e certeza que esse tipo de pratica pode ser um jogo perigoso.
Acho que o maior problema tem sido programadores que se apegam ao esquema de mockar e acabam usando isso para o que não deveriam. Já vi projeto onde se cria um middleware e depois uma lib que se comunica com ele, na lib o acesso ao middleware é feito através de mock o que não garante nada. Um simples bug na lib Net::Http (e existe muitos) pode passar despercebido.
Isso é como escrever drive para banco de dados, não se pode mockar esse tipo comunicação. Ok a infra estrutura as vezes é complexa de se reproduzir para fazer um teste, mas é o preço que pagamos.
Como disse, FakeWeb é bom, mais cuidado com seu uso.
Olá, Everton
Realmente existe essa questão de “e se tiver um bug na Net::HTTP”. Mas será que a gente deve testar essa classe no nosso código? Será que essa não é uma responsabilidade de quem implementa ela? Você testa que a soma de inteiros funciona na linguagem em que você está trabalhando?
Acho que, quando utilizamos uma classe do sistema, devemos assumir que ela funciona como deveria. Por isso acho razoável mockar a Net::HTTP. Apesar de que lembrei, agora, de uma outra solução para o problema apresentado nesse post, e que vi na biblioteca Restfulie: subir um servidor simples localmente e fazer as requisições para ele.
Uma outra coisa que você disse também é verdade: muitas vezes os desenvolvedores se empolgam demais com os mocks e os usam indevidamente. Mas quando é razoável mockar ou não? Acho que essa é uma questão sem uma resposta definitiva. Será que seu teste é unitário se você não mockar uma dependência? Faz algum sentido mockar num teste de integração?
Acho que seu comentário me fez ver uma distinção melhor de quando utilizar ou não FakeWeb. Agora acho que só o usaria num teste unitário de uma classe intermediária entre o Net::HTTP e minha aplicação. Num teste de integração, utilizaria um servidor local.
Enfim, obrigado pelo comentário!
Concordo plenamente, tanto coma questão de que não é responsabilidade do desenvolvedor o teste de bibliotecas de terceiros, quanto com a questão de utilizar um servidor local nos testes de integração.
O que fizemos no Restfulie é uma prática que já tínhamos usado em outros projetos, inclusive existe coisas como rack/test que ajudam muito na hora de consumir uma aplicação dentro de outra via http, você elimina a necessidade de levantar um serviço, e não fica dependente de uma biblioteca http, mas faz as requisições chegarem a quem vai realmente responder por elas e aumenta a qualidade do teste de forma considerável, o único problema neste caso é que sua arquitetura tem que ser com base em rack, mas a idéia por trás disso é sensacional.
A questão dos testes de terceiro é um pouco mais complicada, Net::Http é conhecidamente bugada, e esse pré conhecimento me leva a pensar que as vezes mesmo não sendo obrigado a testar, devemos tomar cuidado com esse tipo de lib, quando uso ActiveRecord tenho confiança de que os bugs são mínimos por saber que ela é bem coberta por testes e esta em constante desenvolvimento, o mesmo não se aplica com Net::Http.
Mas toda essa discussão tem como base a questão do discernimento pelo desenvolvedores, o que em geral, tem falhado miseravelmente, rsrsrs
Ah, então você trabalha no Restfulie! Legal!
Acho que concordo com você: se as classes dos terceiros são conhecidamente bugadas, é bom fazer um teste sem usar mocks no lugar delas. Mas não sabia que a Net::HTTP era bugada, assim.
Mas, como você disse, essa discussão tem muita base no discernimento de cada desenvolvedor. Isso é algo muito subjetivo, então acho que não há uma resposta definitiva para os problemas. Pelo menos não enquanto não inventarem uma medida absoluta para esses aspectos do software…
Abraço!
Leave a reply