Teste unitário de actions

[quote=carneiro]javaBeans é uma especificação falida de Sun

PC, por que uma especificação fálida?

Explique melhor, kra, porque eu vejo os javaBeans como extremamente úteis e como uma boa prática de programação.[/quote]

Voce esta falando de pojos simplesmente. Eh o que o Java te proporciona, gostem ou nao.

Rafael

Certo, certo, só não entendi porque o Mauricio e o PCalcado disseram que não é boa prática fazer javabeans.

Sinceramente, não vi pq nao seja.

Ninguem falou que eh “ma pratica”. O Phillip apenas frizou que o melhor, atualmente, eh chamar de objeto de negocio, ao inves de “javabean”. O conceito original de “javabean” ja se perdeu no tempo. Hj em dia eh apenas uma classe java “simples”, “pura”…

Liberte a mente :slight_smile:

Rafael

Procurando no GUJ, encontrei esse post aqui: http://www.guj.com.br/posts/list/6833.java

A action abaixo implementa lógica ??? add, remove, alterar ???

Quero entender o limiar entre ter lógica na action e não ter lógica na action para decidir se volto para servlets puros ou não.

[color=red]Algúem poderia dar um exemplo do que seria uma action pecadora com lógica dentro e o que seria uma puritana sem lógica dentro ???[/color]

 public class GerenciarUsuario extends ActionSupport implements UsuarioAware, UsuarioDAOAware {
 
   private Usuario usuario;
   private UsuarioDAO dao;
 
   public void setUsuario(Usuario u) {
     this.usuario = usuario;
   }
 
   public Usuario getUsuario() {
     return usuario;
   }
 
   public void setUsuarioDAO(UsuarioDAO dao) {
     this.dao = dao  }
 
   public UsuarioDAO getUsuarioDAO() {
     return dao;
   }
 
   public String adicionar() throws Throwable {
      try {
         dao.adicionar(usuario);
         return SUCCESS;
      } catch(DAOException e) {
         addError(getText(e.getMessage()));
         return ERROR;
      }
   }
 
   public String remover() throws Throwable {
      try {
         dao.remover(usuario);
         return SUCCESS;
      } catch(DAOException e) {
         addError(getText(e.getMessage()));
         return ERROR;
      }
   }
 
   public String alterar() throws Throwable {
      try {
         dao.alterar(usuario);
         return SUCCESS;
      } catch(DAOException e) {
         addError(getText(e.getMessage()));
         return ERROR;
      }
   }
 }

Eu não sei quem recomendou, mas no meu “Hibernate in Action” é assim. No filtro só tem “doFilter()”, “commitTransaction()” e “closeSession()”, nessa ordem. Ele não abre sessão no filtro.

Pois é, só que até ter uma conexão denovo, ela não serve pra nada além de manter o controle sobre os objetos persistentes.

Sei lá, no Spring é assim também, pra métodos transacionais que não exigem uma transação anterior e funciona. Eu também uso e funciona normalmente pra mim.

[quote=Rafael Steil]Ninguem falou que eh “ma pratica”. O Phillip apenas frizou que o melhor, atualmente, eh chamar de objeto de negocio, ao inves de “javabean”. O conceito original de “javabean” ja se perdeu no tempo. Hj em dia eh apenas uma classe java “simples”, “pura”…

Liberte a mente :slight_smile:

Rafael[/quote]

Disse tudo :mrgreen:

Quando eu falo bean (nunca falei javabean), é claro que é POJO e não JavaBean ou EJB.

Nego saiu pela tangente com o assunto de JavaBeans e confundiu a cabeça do Carneiro. (E provavelmente a minha tb…)

Vamos focar no assunto em questão que já tá polêmico demais…

Link: http://www.hibernate.org/hib_docs/v3/reference/en/html/transactions.html

e mais importante:

[quote=saoj] A action abaixo implementa lógica ??? add, remove, alterar ???

Quero entender o limiar entre ter lógica na action e não ter lógica na action para decidir se volto para servlets puros ou não.

Algúem poderia dar um exemplo do que seria uma action pecadora com lógica dentro e o que seria uma puritana sem lógica dentro ??? [/quote]

Pense no seguinte, se não fosse no Mentawai, ou pior ainda, se não fosse web, a lógica funcionava?

[quote=saoj]Link: http://www.hibernate.org/hib_docs/v3/reference/en/html/transactions.html

e mais importante:

[/quote]

Pronto, então no Hibernate vai dar no mesmo. Mas eu prefiro não abrir :lol:

[quote=Maurício Linhares]
Pense no seguinte, se não fosse no Mentawai, ou pior ainda, se não fosse web, a lógica funcionava?[/quote]

Fiquei na mesma, Maurício.

A action que eu postei é do WebWork.

Qualquer lógica vai funcionar em qualquer caso, desde que vc dê a ela o que ela necessita.

Acho que eu entendi a vantagem de não usar o Input e sim Injection: aquela action não vai depender do input do mentawai.

Mas o que eu realmente não entendo é: a porcaria da action não extends ActionSupport não já tá atrelada ao framework de qualquer jeito ??? Esse negócio de fazer as coisas totalmente independentes de tudo, que podem ser migradas pra tudo que é canto não está com nada.

Quem realmente precisa disso ??? Quem realmente precisa pegar sua action e colocar para rodar em Swing ???

Se vc quer fazer um front-end com swing para o seu sistema, faça requisições HTTP para o seu servidor e apenas exiba os resultados num componente Swing. :? E seja feliz !!! :lol:

[color=red]To começando a achar que eu viajei. Eu nunca quis botar lógica dentro da minha action. Quer dizer, fiquei tentando no caso do LoginAction de acessar o DB diretamente, mas do resto eu acho que é pra fazer como essa action do webwork que eu postei. E usar o bom senso tb. Do jeito que vcs falam parece que é proibido qualquer IF ali dentro. :lol: [/color]

[quote=saoj] Mas o que eu realmente não entendo é: a porcaria da action não extends ActionSupport não já tá atrelada ao framework de qualquer jeito ??? Esse negócio de fazer as coisas totalmente independentes de tudo, que podem ser migradas pra tudo que é canto não está com nada.

Quem realmente precisa disso ??? Quem realmente precisa pegar sua action e colocar para rodar em Swing ??? [/quote]

Ave maria, calma! :lol:

A Action vai pro lixo Sérgio, não me interessa reaproveitar a Action, o que me interessa é reaproveitar a lógica de negócio, que é ver se o usuário está cadastrado e logar ele no sistema, colocando ele na “coleçãoDeUsuáriosLogados”. A Action é só um objeto Command e isso agente nunca reaproveita. Ou alguém já reaproveitou?

Eu vi um pessoal desenvolvendo uma aplicação de automação comercial onde era muito importante que ela fosse tanto web quanto desktop, então eles separaram a lógica assim. Ela havia sido feita pra web com Struts, no desktop era Swing. Os actions do Struts só chamavam as classes de negócio, toda a lógica, acesso a bancos de dados e o resto das coisas eram feitos fora do Struts, no fim, ele reaproveitaram praticamente tudo da versão web.

Desulpe o nervosismo gerado pela minha ignorância.

Estou mais calmo agora, pois acho que viajei. Não preciso voltar para o servlet puro, pois as actions podem ser mais que simples controlodoras burras.

Eu nunca quis botar lógica dentro da minha action. Quer dizer, fiquei tentando no caso do LoginAction de acessar o DB diretamento, confesso! Mas do resto eu acho que é pra fazer como essa action do webwork que eu postei. E usar o bom senso tb. Do jeito que vcs falam parece que é proibido qualquer IF ali dentro.

Vcs tem razão: acesso ao banco dentro da action é feio. ConnectionFilter foi um erro pois passa a impressão que usar a Connection dentro da action é legal. Acredito que mudar o filtro para ele adicionar a connection (ou a session do hibernate) no thread local resolve tudo. (Espero!!! Se não resolver falem! :slight_smile: )

O que eu vou falar agora ou vai ajudar a esclarecer ou vai f%$&er tudo de vez :mrgreen:

Existe outra divisão em um sistema. A divisão de domínios.

Domínio Fundamental
Classe fundamentais, utilizadas em diversos sistemas.
Integer, Boolean, String, BigDecimal…

Domínio de Arquitetura
Um pouco mais alto nível lida com coisas relativas á arquiteura da aplicação. Reutilizáveis por diversas aplicações em diversas indústrias. Incluem classes para conexão entre máquinas, acesso a base de dados, interfaces…
RMI, JDBC, HttpServlet…

Domínio de Negócios
Classes específicas do negócio. Contêm os relacionamentos e regras de negócio do domínio em questão. O Domain Model. Pode ser utilizado para construir diversas aplicações.
Cliente, Venda, Pedido, ClienteDAO etc.

Domínio de Aplicação
Classes e componentes relativos à uma aplicação. Gerenciadores de eventos que sabem responder a estímulos. Sabem que se o usuário submeter o link XYZ ou clicar no botão ABC é para informar ao domínio de baixo sobre a ciração de um novo pedido. Não são reutilizados fora da aplicação.
Action, GerenciadorClientes, JSPs, AdicionarClienteServlets…

Resusabilidade, do pior para o melhor:
Aplicação -> Negócios -> Arquitetura -> Fundamental

Vejamos. É importante, então, isolarmos as regras de negócio no domínio de negócios, porque estas são reutilizáveis. (e flexíveis). A aplicação nem tanto.

Existe quem goste de colocar todo o domínio de aplicação na camada web, com um framework MVC qualquer. Isso abaixa ainda mais a reusabilidade da aplicação, mas essa já não era alta. Geralmente se você precisa reutilizar regras da aplicação, é porque estas regras são do negocio, não da aplicação. Refatore.

Eu pessoalmente gosto de colocar o mínimo possível na interface e criar classes Gerenciadores (estou querendo me livrar disso, mas aidna não achei solução melhor) que possuem métodos para realizar as etapas (adicionaUsuario(Usuario u), etc.). Assim a reusabilidade é maior, crieo, e muitas vezes já fiz aplicações com mais de uma interface (mais de cinco até!) para a mesma regra de negócios.

Ah, para mais sobre o assunto, leiam esse livro :wink:

Olá! (òtimo tópico hein!)

Concordo, e assim basta usar o junit para mim testar minhas actions. Não precisaremos de mocks implementando Input ou Output. Apenas precisaremos criar mocks para classes de negócios ou de persistências da aplicação que ainda não foram desenvolvidos, ou para garantir maior performance durantes a execução dos testes unitários!

Um sistema bém testado (suponho que com este post vc quer atingir programadores que saibam testar e desenvolver com qualidade), é bém provavel que o código estará bém desacoplado e as lógicas de negócio estaráo nos seus devidos lugares. De certa forma, para que seja fácil e produtivo testar, as divisões de responsabilidades do sistema deverão estar bém definidas.

Sendo assim, se precisar mover minha app de web para swing, um refactoring é mais que suficiente. Meus testes vão me dar o feedback que preciso para ter certeza que o refactoring está acontecendo com sucesso!

Ainda prefiro o refactoring! Já que é uma apicação swing, preferiria poupar este processamento e buscar algo mais ágil. :wink:

Bom, minha opinião.
Abraços!
Thiago Senna

Eu posso estar viajando no que vou dizer a seguir, mas depois de ler este tópico e outros (principalmente sobre testes unitários) minha cerebro está quase derretendo. :oops:

Uma action é o lugar onde devemos colocar a lógica de controle, então ela não deve realizar outras tarefas e por isso os seus teste unitários devem conter apenas teste de lógica.

[quote=saoj]
…Mas do resto eu acho que é pra fazer como essa action do webwork que eu postei… [/quote]

Essa action é simples, mas mesmo assim e se tivermos de fazer coisas com autenticar o usuário antes da requisição, verificando se ele tem permissão para aquela ação, ou registar aquela ação em um BD, como seria o teste? E nossa action não passaria a depender de outros DAOs? :shock:

Eu andei dando uma olhada no pattern Chain of Responsibility que pode ser facilmente implementado com essa biblioteca da Jakarta. Vejam um exemplo:

[code]public class GerenciarUsuario extends ActionSupport {

public String adicionaUsuario = "AdicionarUsuario";

public String adicionar() throws Throwable {

    try {

        Command chain = ChainFactory.getChain(adicionaUsuario);
        ActionContext context = new ActionContext();
        context.put("usuario", usuario);
        
        if (chain.execute(context)) {
            return ERROR;
        }
        return SUCESS;

    } catch (Exception e) {
        addError(getText(e.getMessage()));
        return ERROR;
    }
}

}[/code]

Onde podemos, na classe que irá implementar os testes unitários, redefinir a string da variável adicionarUsuario da action por algo do tipo “AdicionaUsuarioMock” (não consegui imaginar uma forma melhor de fazer isso :oops: ), facilitando a criação e a chamada da classe Mock que irá simular o comportamento da série de commands que teriamos que chamar.

Desta forma eu acredito que teremos uma maior reusabilidade dos objetos da camada do “Domínio de Negócios” e um baixo acoplamento entre eles e a action, através de classes que implementem o pattern Command e ficariam responsáveis por chamar os objetos. Além de facilitar imensamente a alteração (inclusive da ordem de chamada), inclusão e exclusão desses “commands”.

Outra coisa que me deixa com um :?: na cabeça. Os testes unitários devem testar a funcionalidade de uma classe específica, e por isso criamos essas classes Mocks para simular as funcionalidades das classes que ela depende. Agora se criassemos Mocks para os DAOs da action acima, como saberiamos que eles estariam acessando corretamente a informação? Tudo bem, quem é responsável por isso é o DAO e não a action. Mas e o DAO, se substituirmos o SGBD por uma classe Mock, como teremos certeza que o mapeamento XML (como no caso do Hibernate), ou as querys estão corretas. Não seria correto testar diretamente com o BD, como disse o Sérgio, ou isso seria testes de integração?

Estou cada vez mais fascinado por este novo mundo, cercado de patterns e testes por todos os lados :smiley: . Só que não consigo para de pensar se, por empolgação, não estou “matando mosca com tiro de canhão” :mrgreen: e fazendo mau uso desses padrões, quase como uma orverdose.

Será que vocês, gurus aqui do GUJ poderiam me dizer se pelo menos estou no caminho certo e conseguindo entender o que vocês estão dizendo aqui no Forum.

Abraços

Várias coisas que eu vou pesquisar:

:arrow: O JMock facilita a criação de mocks pra tudo, desde que vc programe seu model de negócios em cima de interfaces e com IoC, isto é, essas interfaces do model são injetadas de alguma maneira nas suas actions. (É isso Phillip?)

:arrow: Model-driven do WW. Te permite dar um bypass na action injetando o input direto no model de negócios.

:arrow: Quando for testar os DAOs, acho que vc precisa testar eles com o banco de dados. Nem que seja um banco de testes igual ao de produção. Se não é o que vc falou…

:arrow: Chain of Resonsability parece legal, mas se o JMock resolve o problema dos mocks, então prefiro trabalhar com mais liberdade usando interfaces mesmo.

Eu acho que isso deve estar em filtros, não na action.

[quote=debersom]

Eu andei dando uma olhada no pattern Chain of Responsibility que pode ser facilmente implementado com essa biblioteca da Jakarta. Vejam um exemplo:[/quote]

Posto dessa forma nao tem muita vantagem, ja que vc estara simplesmente criando um passo a mais ate chegar a acao de fato. Uma maneira melhor seria fazer a action ja acessar os services.

[quote=debersom]
Outra coisa que me deixa com um :?: na cabeça. Os testes unitários devem testar a funcionalidade de uma classe específica,
[ … ]
Mas e o DAO, se substituirmos o SGBD por uma classe Mock, como teremos certeza que o mapeamento XML (como no caso do Hibernate), ou as querys estão corretas. [/quote]

Voce nao vai poder usar mock - vai ter que ir ao banco de dados mesmo.

Rafael

Sim, os mock dinâmicos em geral facilita a criação de qualquer coisa. Mas na minha opinião quando eu estiver testando uma Action no Mentawai, eu quero criar os mocks para os DAO’s e outras classes que a Action usa. Eu não quero um mock para minha própria action.

Quando faço os testes do DAO, eu testo ele acessando o banco. Por natureza, de acordo os testes vão crescendo, a tendência é eles demorarem mais em comparação com outros testes.

Eu tenho o habito de criar um teste suite para o teste dos DAO’s. Assim quando eu estiver testando outras áreas do sistema, eu consigo tem testes mais rápido.

Se durante os testes das actions eu ficar acessando os DAO’s que possuem acesso ao banco, o teste das actions também ficarão lentos. Por isso eu utilizo mocks dinâmicos para implementar as interfaces dos DAO’s quando estou testando minhas actions, já que aqui meu objetivo não é testar os dao’s, já que eles estão sendo testados em outro lugar!

Oi,

O Jmock facilita a criação de mocks e asserção. Não é o único, mas eu tenho usado bastante.

Você não precisa ter apenas interfaces, basta usar o pacote opcional da CGLIB.

Sobre testes, aquele livro chato do pressman tem muita coisa. Outros também, claro, tire aquele livro empoeirado de Engenharia de Software da estante.