Em implementações de testes unitários é necessário utilização de conexão com o banco?

Eu tinha participado de um treinamento por uma empresa no paraná de teste unitários com Junit, porém o treinamento necessitava de conhecimento prévio, não tive chances de me aprofundar pra valer.

Atualmente a empresa solicitou para mim implementar testes unitários no projeto que estou participando, e tinha muita coisa que eu precisei relembrar.

No treinamento e no atual projeto que participo usasse Spring.

Eu tentei configurar os testes unitários para aceitar a anotação do porque estava dando NullPointException

@Autowired

E meu gestor disse que toda vez que utilizasse essas anotação é porque ele vai fazer uma consulta no banco, pois os dados tem que ser mockados .

  1. eu gostaria de saber se isso que ele está certo!

  2. Outra dúvida que preciso tirar é saber se é recomendado que os testes sempre sejam testes que não tenham utilização da conexão com o banco!

Observem o método abaixo;

public void importarIndicios(List indicios,
UsuarioLogados usuarioLogado) throws PrincipalException {

    for (final IndicioEntity indicio : indicios) {
        indicio.setDataUltimaMovimentacao(getDataAtual());
        final SituacaoIndicioEntity situacao = new SituacaoIndicioEntity();
        situacao.setCodigo(1);
        indicio.setSituacaoAtual(situacao);
        this.inserir(indicio);// salvar indicios

        final HistoricoEntity historico =
                new HistoricoEntity();

        historico.setCodigoUsuario(usuarioLogado.getCodigo());
        historico.setCodigoIndicio(indicio.getCodigo());
        historico.setCodigoSituacaoIndicio(
                indicio.getAtual().getCodigo());
        historicoSituacao
                .setData(indicio.getDataUltima());

        historicoService.inserir(historico);
    }

}

Você percebe que o método tem uma assinatura que recebe uma lista de indícios e recebe dados do usuário logado, porém na assinatura não tem como receber o histórico, como realizar um teste unitário com mockito sem ter acesso ao banco nesse contexto?

O conceito de teste unitário que eu conheço dispensa conexões e interações entre camadas distintas.
Essa é a parte dos testes integrados e de aceitação.
Se você precisa se conectar ao banco, já está integrando duas partes distintas do software, logo, não é mais unitário.
A ideia de teste unitário deveria, ao meu ver, consistir em testar a menor unidade lógica testável, ou seja, um método específico. “Ah, mas esse método é o que chama a camada de persistência”. Sim, para isso existe o bom e velho mock, que deve substituir a interação com a base de dados.

Porém, esse é apenas meu dedo de opinião…

1 curtida

Eu não sei se já usou Spring, baseado nesse teste abaixo você acha que ele está utilizando conexão com o banco de dados;

@ContextConfiguration(locations = { "classpath:applicationContext.xml", "file:resources/struts.xml",
		"file:resources/tiles.xml", "file:WebContent/META-INF/context.xml"

})

@RunWith(SpringJUnit4ClassRunner.class)
@Sql(statements = { 
        "INSERT INTO TipoIndicios (Codigo,Nome) VALUES (1,'segundo  grupo')",
        "INSERT INTO TipoIndicios (Codigo,Nome) VALUES (2,'primeiro  grupo')",
        "INSERT INTO TipoIndicios (Codigo,Nome) VALUES  (3,'Grupo 1')",
        "INSERT INTO TipoIndicios (Codigo,Nome) VALUES  (4,'Grupo 2')",
        "INSERT INTO TipoIndicios (Codigo,Nome) VALUES  (5,'Grupo 3')",
        "INSERT INTO TipoIndicios (Codigo,Nome) VALUES  (6,'Grupo 4')",
        "INSERT INTO TipoIndicios (Codigo,Nome) VALUES  (7,'Grupo 5')"
         })
public class IndiciosTestDAOTest {

    @Autowired
    private IndicioDAO indicioDAO;

    @Test
    public void findByIdIndicio() {
        IndicioEntity result = indicioDAO.getPorId(1);
        assertThat(result, notNullValue());

    }

Dentro do ponto de vista do meu gestor a anotação Autowired é desnecessário já que não existe necessidade de conexão com o banco de dados.

Eu gostaria de saber se ele está certo!

É porque eu precisei que ele estivesse funcionando, no treinamento que recebi a anotação Autowired era indispensável, e eles afirmavam eram dados mockado.

Eu concordo com ele.
De novo, minha visão sobre testes unitários é que: você deve mockar o objeto indicioDAO, logo, ele não pode ser injetado.

1 curtida

Existem vários artigos e tutoriais a respeito (nessa pesquisa, descobri que tem cursos específicos na udemy sobre).
Porém, esse aqui do Baeldung é bem legal e dá uma boa noção sobre tudo o que comentei.
É em inglês, mas, fácil de entender.

1 curtida

Teste unitário, como @darlan_machado falou, serve para testar regra de negócio. Se você está com dificuldade de fazer teste unitário, provavelmente tem um problema de design.

A função importarIndicios que você mostrou, por exemplo, tem lógica de negócio (alterar a data da última movimentação, alterar o código, alterar a situação, mexer no histórico, etc.) e detalhes operacionais (salvar no banco, por exemplo). São esses detalhes operacionais que dificultam o teste e fazem com que você precise sair fazendo mocks. Você poderia extrair a lógica para uma função pura, o que seria muito mais fácil de testar com testes unitários.

1 curtida

Em teoria ele está certo, mas na prática pode não valer o esforço esse teste fake, e sim fazer teste funcional.

Considere o que o @lvbarbosa disse.
Se você pensar assim, sempre concluirá que testes unitários, integrados, de aceitação, etc, não vale a pena. Afinal, o usuário vai usar e se aparecer algum bug, corrige-se.

Veja, cada tipo específico de teste foi devidamente planejado e (ohhhh) testado ao longo de muitos anos.
O que provavelmente ocorre é que a divisão das responsabilidades em cada uma das tuas pequenas unidades testáveis (os verdadeiros alvos dos testes unitários) esteja fora do adequado. Ou seja, você está fazendo com que um método e/ou classe façam coisas que não lhes cabem, quebrando, assim, a possibilidade de testar a funcionalidade individualmente.

Se o teste funcional cobrir não precisa de teste unitário.

@javaflex, é difícil uma empresa não possuir toda uma estrutura com um time de QA. Assim sendo, não há necessidade de testes unitários, nem integrados, nem quaisquer outros, senão as regressões.

Não falei de não possuir, muito pelo contrário, mas o foco é funcional. Se tem uma tela, testa a tela, se é uma API que um terceiro vai usar, testa a API, etc.

@javaflex, eu entendi. Mas, se a ideia do teste funcional é assimilar o que o teste unitário faria, evitando assim trabalho dobrado, então esquece tudo e só testa com a regressão.
Porém, conceitualmente falando, testes unitários e testes funcionais são bem diferentes e, no meu entendimento, complementares, não excludentes.
O teste unitário é, sim, parte da atividade do dev. De que outra maneira ele garante que desenvolveu adequadamente, aplicou os requisitos e as regras de negócio? Obviamente que teste unitário (e mesmo teste funcional) não garantem boa qualidade de código, haja visto que um mesmo problema pode ter 200 soluções, sendo que, destas, só 3 ou 4 são boas.

Agora, se estamos falando de testes unitários como os que eu vi por aí, sim, não tem necessidade. Vários com @Test sem assertions ou assertions comentadas.

Se esses testes fakes sao úteis pra voces ok. Na última experiência que tive eles foram abandonados já que os funcionais cobriam mais a realidade de uso em sistemas de informações.

Feedback constante com o cliente usando o que está sendo prototipado e desenvolvido. Nenhum desses testes garantem isso, por mais que o teste passe de acordo com o que o programador entendeu ou o que o próprio cliente achava que deveria ser inicialmente.

Desculpem a todos… mas o que está em questão não é a importância dos testes unitários ou testes funcionais, e sim, se existe algo errado de realizar testes de integração com banco de dados nos testes unitários, pelo que entendi, foi de opinião unânime que não é certo fazer testes de integração com banco de dados, e sim realizar teste mockados.

Eu fiz umas pesquisas de ontem para hoje e encontrei informações muito importantes, e nessa opinião que vou expor nesse momento não estou levando em consideração se testes funcionais são mais importantes que testes unitários, ou vice e versa.

Infelizmente todos que deram opinião da maioria estão equivocados quando se trata se é necessário realizar testes unitários de integração banco de dados, e eu não sabia o que era certo, mas eu tenho no meu Linkedin um grupo de colegas que são arquitectos de sistemas com quem pude contar com eles essa semana e me explicaram o seguinte…

De fato para realizar teste que sejam para as classes de serviços e a classe de controller, no nosso contexto a classe de controller é o IndicioProcessoAction, elas precisam ser implementadas realmente com o mockito, porém isso não se aplica para a classes do pacote DAO.

As classes do pacote DAO estão especificamente testando as query nessas são implementadas através do Hibernate, para isso é necessário a injeção de dependências através da anotação Autowired, sabendo disso podemos concluir que os teste realizando na classes do pacote DAO sempre serão de integração com banco de dados.

Apesar disso eu não posso atrapalhar o banco de dados que esta configurado da minha máquina que seja mysql, postregresql ou oracle, então quando é executar os testes, meu projeto precisa saber que é um teste e não deve acessar esses bancos. Ele tem que acessar um banco em MEMRÓRIA, pra não afetar meu trabalho.

Com isso concluirmos que o projeto precisa de um banco de dados em mémoria, e em empresas que aplicam a métodologia agil da forma correta da mesma forma que é sempre recomendável que testes da classe DAO sejam de integração e sempre recomendável que nos testes de integração seja utilizado o banco de dados H2, que é um banco em mémoria, não deixando de salientar e existem outros banco de dados em memória.

Se os testes realizados no projeto que estou incluído forem feitos mockados nas classes DAO e não forem testes de integração em banco em memoria com certeza, sem nenhuma zombra de dúvidas esse teste não serão testes validos.

O que endossa tudo que falei está nesse artigo logo abaixo;

# How you should unit test DAO layer

1 curtida