Testar parametros nulos em testes unitários

Pessoal,

 Tenho uma dúvida em relação a testes unitários. Imagine que tenho o seguinte metodo:
public class MinhaClasse {
 
    public void fazerAlgumaCoisa(String a, Long b, Long c){
        System.out.println("Executando o método...");
    }
    
}
 Minha dúvida é o seguinte, devo ficar testando se os parâmetros são nulos ou coisa assim? Ou seja, devo criar os testes abaixo? Ou devo testar apenas regras de negócio e deixar validações de parâmetros?
public class MinhaClasseTest {
    
    public MinhaClasseTest() {
    }
    
    @Test
    public void naoDeveFazerNadaSeOParametroAForNulo() {
        System.out.println("Executando teste");
    }
    
    @Test
    public void naoDeveFazerNadaSeOParametroBForNulo() {
        System.out.println("Executando teste");
    }
}

A resposta é sempre um grande: DEPENDE.

Pense que ao escrever um teste unitário, você está definindo o comportamento do seu método. Se você precisa prever/determinar um determinado comportamento para um valor nulo então você deve escrever esse teste, caso contrário, pode ser que você esteja sendo redundante.

Olá rmendes, valeu pela resposta. Na verdade a validação desses parâmetros seriam pra evitar um possível NullPointerException.

Certo, digamos que você faça essa validação para evitar o NullPointerException, qual seria o comportamento do método então ?

Um exemplo mais concreto:

public class Calculadora {
    
    public Long dividir(Long a, Long b){
        return a / b;
    }
    
}
public class CalculadoraTest {
   
    @Test
    public void naoDeveDividirSeAForNulo() {
        Calculadora calculadora = new Calculadora();
        Long divisao = calculadora.dividir(null, 10l);
        assertNull(divisao);
    }
}

[quote=anderson_lr]Um exemplo mais concreto:

public class Calculadora {
    
    public Long dividir(Long a, Long b){
        return a / b;
    }
    
}

[code]
public class CalculadoraTest {

@Test
public void naoDeveDividirSeAForNulo() {
    Calculadora calculadora = new Calculadora();
    Long divisao = calculadora.dividir(null, 10l);
    assertNull(divisao);
}

}
[/code][/quote]Mas desse modo seu teste vai falar por que você terá uma exception.
Troque para @Test(expected=NullPointerException.class) e seu teste passa.

[quote=anderson_lr]Um exemplo mais concreto:

public class Calculadora {
    
    public Long dividir(Long a, Long b){
        return a / b;
    }
    
}

[code]
public class CalculadoraTest {

@Test
public void naoDeveDividirSeAForNulo() {
    Calculadora calculadora = new Calculadora();
    Long divisao = calculadora.dividir(null, 10l);
    assertNull(divisao);
}

}
[/code][/quote]

Não entendi, o nome do seu teste diz que naoDeveDividirSeAForNulo, mas o teste em si permite que essa divisão seja feita ?!

Repare que o compilador não pode verificar a semântica entre métodos e tipos de retorno. No nível da linguagem de programação, uma operação que retorna null é uma operação igualmente válida, diferentemente de uma operação que lança uma NullPointerException. Assim, nem sempre é bom negócio evitar NullPointerException. Justamente porque elas acusam o local exato do erro.

Pessoa, era só um exemplo, um exemplo mais concreto seria esse:

public class Calculadora {
    
    public Long dividir(Long a, Long b){
        if(a == null || b == null){
            return null;
        }
        return a / b;
    }
    
}
public class CalculadoraTest {
   
    @Test
    public void naoDeveDividirSeAForNulo() {
        Calculadora calculadora = new Calculadora();
        Long soma = calculadora.dividir(null, 10l);
        assertNull(soma);
    }
    
     @Test
    public void naoDeveDividirSeBForNulo() {
        Calculadora calculadora = new Calculadora();
        Long soma = calculadora.dividir(10l, null);
        assertNull(soma);
    }
}

[quote=anderson_lr]Pessoa, era só um exemplo, um exemplo mais concreto seria esse:

public class Calculadora {
    
    public Long dividir(Long a, Long b){
        if(a == null || b == null){
            return null;
        }
        return a / b;
    }
    
}

[code]
public class CalculadoraTest {

@Test
public void naoDeveDividirSeAForNulo() {
    Calculadora calculadora = new Calculadora();
    Long soma = calculadora.dividir(null, 10l);
    assertNull(soma);
}

 @Test
public void naoDeveDividirSeBForNulo() {
    Calculadora calculadora = new Calculadora();
    Long soma = calculadora.dividir(10l, null);
    assertNull(soma);
}

}
[/code][/quote]

é a mesma coisa que eu disse antes …

O que os seus testes estão dizendo é que passar null para o método dividir não é uma situação de erro. O que você fez foi definir que:

  • a divisão de um nulo por não nulo resulta em nulo

e

  • a divisão de um não nulo por nulo resulta em nulo

Sendo assim, os nomes dos testes não condizem com a semântica deles, pois se o que você pretende é tratar os parâmetros nulos como erros você simplesmente deve permitir que as exceções sejam lançadas.

Certo. Depente do que eu espero então:?

public class CalculadoraTest {
   
    @Test
    public void deveRetornarNuloSeAForNulo() {
        Calculadora calculadora = new Calculadora();
        Long soma = calculadora.dividir(null, 10l);
        assertNull(soma);
    }
    
     @Test
    public void deveRetornarNuloSeBForNulo() {
        Calculadora calculadora = new Calculadora();
        Long soma = calculadora.dividir(10l, null);
        assertNull(soma);
    }
}