Unit test with JUnit for system default routines

2

I have a Java code that checks if there are any default categories registered in the database, if it returns true , otherwise it returns false .

public boolean validaEntradaDeDadosPadrao() {
        System.out.println("Entrei aqui");
        Categoria cat = new Categoria();
        boolean condicao = false;
        List<Categoria> categoria = categoriaDao.listaTodos();
        for (Categoria c : categoria) {
            if (c.getNomeCategoria().equals("Financeiro")) {
                System.out.println("tem categorias cadastradas");
                condicao = false;
            } else {
                System.out.println("nao tem");
                condicao = true;

            }
        }
        return condicao;
    }

My unit test looks like this:

@Test
public void testValidaEntradaDeDadosPadrao() {

    boolean primeiraCompilacaoDoProjeto = false;
    boolean compilacoesEmDiante = true;


    Assert.assertEquals(false, primeiraCompilacaoDoProjeto);
    Assert.assertEquals(true, compilacoesEmDiante);

}

I read and saw that unit tests do not query the bank.

I want to know if my test is reasonably good, and what I can improve to make it more consistent.

    
asked by anonymous 01.07.2016 / 21:57

2 answers

5

Introduction

Tests of any kind need to test something. This example is testing nothing.

You can test whatever you want in the test, you can access the database without problems. Of course this is not ideal because tests should ideally run very fast and not have too many dependencies.

To do meaningful and effective testing you need a very good design of the application before anything else. My experience shows that you can only do tests that are worth something when the programmer can already produce good codes. Not that one can not try, but codes full of failures indicate that the programmer has not come to the level of understanding everything that is needed to produce tests. One of these failures is not to separate responsibilities well. Another is to understand the functioning of a language, how the computer works, the complete understanding of basic mathematics.

So let's go.

Your example

Methods should not mix responsibilities. If it is a validator it should not issue messages to the user, this is responsibility of something else, in another class. A validator should only test conditions and tell whether it is right or not.

I imagine the listaTodos() method to access the database. To facilitate the test you need to have a way to call a method that simulates the result in a controlled, fast and without dependencies. One way is to use dependency injection . Another is to completely replace the class of object categoriaDao with a version that does not access the database but rather generates an easily testable result.

There are specific techniques to override the normal behavior of a method .

If you opt for the DI ( dependency injection ) it is quite easy, just receive the object by a parameter. I particularly do not like to change a method just to test, I prefer a more global solution. But it's an option, so you'd have to rethink all the code from all classes to fit the test.

Giving an improvement in other points the method would look like this:

public boolean validaEntradaDeDadosPadrao() {
    for (Categoria c : categoriaDao.listaTodos()) {
        if (c.getNomeCategoria().equals("Financeiro")) {
            return false;
        }
    }
    return true;
}

I preferred not to change the name of the method because I do not know the specification of the problem, but it seems wrong.

Here we can do the test (I'm not saying it's the best way, but a possibility for improvement). I'll post an approximate form here:

class Dao {
    public List<Categoria> listaTodos() {
        list<Categoria> lista = new List<>();
        lista.Add(new Categoria("Financeiro")); //claro que é mais complexo que isto
        lista.Add(new Categoria("OutraCategoria"));
        return lista; //nenhum banco de dados é acessado e provê os dados necessários
    }
}

This class would be the substitute for the original that accesses the database. Of course it would be more complex than that.

Here you would have to create infrastructure to test in different ways, to cause different situations, to create situation that generates a result or another, that can force an error, to make the code execute in any possible way.

@Test
public void testValidaEntradaDeDadosPadrao() {
    Assert.assertEquals(validaEntradaDeDadosPadrao(), true);
}

Here you are testing something useful.

Well, that's more or less. The intention is not to produce the test ready for use, because the question data does not allow this, but rather to give a basic information that the test is done in another way.

    
04.07.2016 / 14:49
4

The idea of assertions is to check whether the behavior produced by the method or class is equivalent to what is expected. First, System.out.println, as bigown commented above, is not necessary, since the idea of automated testing is that it does not require visual verification by a human to determine whether they have passed or failed (in addition to the final report of successes and failures, clear). Second, the method name does not match what it does, it says validate data entry, but in practice what you are doing is selecting the categories of a DAO, and verifying if there is a "Financial". Third, JUnits can access what you want (it's a free world), but whether or not they should access the database depends on the type of test you're trying to accomplish. If what you are wanting is to do Unit Tests, then it is advisable to try to reduce the scope of the test to the maximum, testing only the smallest of the units. In general, for your code, a unit test would use a false implementation of this DAO (which usually does not access a database), which allows the test to inject possible values, or reproduce possible exceptions that are difficult to recreate in a database really. Fourth, try using assertion methods that are closer to what you're trying to test in the test. For example, assertTrue () and assertFalse () are lighter than assertEquals (). Finally, in general you would write at least two unit tests, one for the assertion being true, and one for the assertion to be false.

    
02.07.2016 / 02:14