Skip to content

Instantly share code, notes, and snippets.

@rafaelpontezup
Last active November 12, 2024 18:34
Show Gist options
  • Save rafaelpontezup/ecba938670eb13f876bd279e898b84af to your computer and use it in GitHub Desktop.
Save rafaelpontezup/ecba938670eb13f876bd279e898b84af to your computer and use it in GitHub Desktop.
Quantos e quais cenarios/casos de testes você enxerga para o código da classe ParceladorDeFatura? (adiciona resposta nos comentarios)
package br.com.zup.edu.certificacoes.testing.parcelador;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
public class ParceladorDeFatura {
public static final BigDecimal VALOR_MINIMO_FATURA = new BigDecimal("100");
public static final BigDecimal VALOR_MAXIMO_FATURA = new BigDecimal("100000"); // UPDATED at 2024-10-24
public List<BigDecimal> parcela(BigDecimal valor, int quantidadeDeParcelas) {
if (valor == null) {
throw new FaturaInvalidaException("Valor da fatura não pode ser nula");
}
if (valor.compareTo(VALOR_MINIMO_FATURA) < 0) {
throw new FaturaInvalidaException("Valor da fatura muito baixo para parcelamento");
}
// UPDATED at 2024-10-24
if (valor.compareTo(VALOR_MAXIMO_FATURA) > 0) {
throw new FaturaInvalidaException("Valor da fatura acima do valor máximo para parcelamento");
}
if (quantidadeDeParcelas < 2 || quantidadeDeParcelas > 10) {
throw new FaturaInvalidaException("Número de parcelas deve estar entre 2 e 10");
}
BigDecimal numeroDeParcelas = BigDecimal.valueOf(quantidadeDeParcelas);
BigDecimal valorDaParcela = valor.divide(numeroDeParcelas, 2, RoundingMode.DOWN);
List<BigDecimal> parcelas = new ArrayList<>();
for (int i = 0; i < quantidadeDeParcelas - 1; i++) {
parcelas.add(valorDaParcela);
}
// adiciona resto na ultima parcela
BigDecimal resto = valor.subtract(valorDaParcela.multiply(numeroDeParcelas));
parcelas.add(valorDaParcela.add(resto));
return parcelas;
}
}
@asouza
Copy link

asouza commented Jan 11, 2023

  1. Entrou no primeiro if (valor nulo)
  2. Entrou no segundo if (valor anterior ao minimo)
  3. Entrou no terceiro if pelo lado esquerdo (quantidade = 1)
  4. Entrou no terceiro if pelo lado direito (quantidade = 11)
  5. Entrou no loop uma vez(quantidade = 2)
  6. Entrou no loop rodando duas ou mais vez (quantidade = 10)
  7. Self testing no final para verificar que tem "quantidade" no array

Aí poderia exercitar mais vezes

@rafaelpontezup
Copy link
Author

rafaelpontezup commented Jan 11, 2023

Eu enxerguei 6 cenários/casos de testes:

  1. Entrou no primeiro if (valor nulo);
  2. Entrou no segundo if (valor menor que 100);
  3. Entrou no terceiro if pelo lado esquerdo (quantidade = 1);
  4. Entrou no terceiro if pelo lado direito (quantidade = 11);
  5. Happy-path com valor redondo (valor = 100 e quantidade = 2);
  6. Happy-path com valor quebrado gerando resto (valor = 100 e quantidade = 3);

Contudo....
Podemos resumir em 4 cenários/casos se considerarmos classes de equivalência, ou seja, podemos juntar na mesma classe itens 3 e 4, e também itens 5 e 6.

@mauricioaniche
Copy link

A implementação do método é bem direta. Meu primeiro foco seria testar cada um dos caminhos possíveis nesse método, que são bem claros se vc olhar os ifs do código. Aproveito e sempre que visito um if, olho pro valor de entrada do usuário que ele usa, e analiso o domínio de entrada daquele valor:

  • Linha 14: Valor nulo, teste espera uma exceção
  • Linha 18: Valor menor que 0, teste espera uma exceção, e valor igual a 0 (fronteira da condição), programa não quebra (Não quebra mesmo, me parece estranho parcelar 0 reais...)
  • Linha 18: Me chama a atenção o fato de não ter limite superior para valor. Se esse for mesmo o caso, eu testaria com um valor bem alto (MAX_INT) pra garantir que tudo continua funcionando.
  • Linha 22: Quantidade de parcela igual a 2 e igual a 1 (1 não funciona, 2 funciona). Dois testes aqui pra exercitar a fronteira da condição.
  • Linha 22: Quantidade de parcela igual a 10 e igual a 11 (10 funciona, 11 não funciona). Dois testes aqui pra exercitar a fronteira.

A partir daqui o método tem um caminho único. Olhando a implementação, entendo que o código divide o total entre o número de parcelas pedido, adiciona qualquer diferença na última parcela. Regras de arredondamento são duas casas decimais e arredondar pra baixo.

Pensando nas principais variáveis que estão em jogo aqui:

  • Última parcela: Última parcela que seja um pouco maior do que as anteriores, e última parcela que seja igual as anteriores. Pensaria aqui também se é possível que a última parcela seja um pouco menor, mas como arredondamos pra baixo, acho que não é possível.
  • Arredondamento: caso onde o número seja forçado a arredondar pra baixo
  • Número de parcelas: 2, 10 (limites), um número no meio ("in point") qualquer apenas pra garantir.

Não consigo pensar em mais nada. Agora é só transformar esses casos de teste em testes automatizados. Se rodar cobertura de código aqui, espero que bata 100%. Se não bater, olhar o que faltou.

Esse método é um excelente caso também para property-based tests. A propriedade é direta, e bem fácil de ser implementada: dado qualquer número de parcelas entre 2 e 10, e qualquer valor maior do que zero, a soma das parcelas geradas tem que ser igual ao valor inicial.

PS: Vc não precisa de testes repetidos. O teste com 2 parcelas que sugeri no começo pode ser o mesmo teste que sugeri quando explorei o "caminho feliz" do método. Quando estou pensando nos casos de testes, não me preocupo muito em encontrar "o menor conjunto de testes", a limpeza acontece depois.

@kewers
Copy link

kewers commented Jan 16, 2023

A : BigDecimal
B : Int
1. A == null ==> Exception
2. A < 100   ==> Exception
3. B < 2     ==> Exception
4. B > 10    ==> Exception
5. Para todo (A : BigDecimal) e (B : Int), onde A!= null, e A >= 100, e B >= 2, e B <= 10, 
    somaLista(parcela(A,B)) == A
    length(parcela(A,B)) == B

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment