Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Evitando duplicação de código nos testes

Fiz uma implementação um pouco diferente, visando evitar duplicação de código. Gostaria que vcs opinassem.

package br.com.caelum.leilao.servico;

import static org.hamcrest.Matchers.closeTo;
import static org.junit.Assert.assertThat;

import org.junit.Test;

import br.com.caelum.leilao.dominio.Leilao;
import br.com.caelum.leilao.dominio.LeilaoDataBuilder;
import br.com.caelum.leilao.dominio.LeilaoDataBuilder.Ordem;

public class AvaliadorTest {

    @Test
    public void deveAcharValoresEmOrdemCrescenteDeLances(){
        Avaliador avaliador = criarAvaliadorcomLeilaoTendoLancesEmOrdem(5, Ordem.CRESCENTE);

        assertThat(avaliador.getMaiorLance(), closeTo(5, 0.0001));
        assertThat(avaliador.getMenorLance(), closeTo(1, 0.0001));
        assertThat(avaliador.getLanceMedio(), closeTo(3, 0.0001));
    }

    @Test
    public void deveAcharValoresEmOrdemDecrescenteDeLances(){
        Avaliador avaliador = criarAvaliadorcomLeilaoTendoLancesEmOrdem(5, Ordem.DECRESCENTE);

        assertThat(avaliador.getMaiorLance(), closeTo(999_999, 0.0001));
        assertThat(avaliador.getMenorLance(), closeTo(999_995, 0.0001));
        assertThat(avaliador.getLanceMedio(), closeTo(999_997, 0.0001));
    }

    @Test
    public void deveAcharValoresComUnicoLance(){
        Avaliador avaliador = criarAvaliadorcomLeilaoTendoLancesEmOrdem(1, Ordem.CRESCENTE);

        assertThat(avaliador.getMaiorLance(), closeTo(1, 0.0001));
        assertThat(avaliador.getMenorLance(), closeTo(1, 0.0001));
        assertThat(avaliador.getLanceMedio(), closeTo(1, 0.0001));
    }


    private Avaliador criarAvaliadorcomLeilaoTendoLancesEmOrdem(int lances, Ordem ordem) {
        Avaliador avaliador = new Avaliador();
        Leilao leilao = LeilaoDataBuilder.builder()
                .comNumeroLancesIgualA(lances)
                .na(ordem)
                .build();

        avaliador.avaliar(leilao);

        return avaliador;
    }
}

package br.com.caelum.leilao.dominio;

import java.util.stream.IntStream;

public class LeilaoDataBuilder {
    private String nomeLeilao = "Playstation 4";
    private Ordem ordem = Ordem.CRESCENTE;
    private int numeroLances = 3;

    public LeilaoDataBuilder com(String nome){
        this.nomeLeilao = nome;

        return this;
    }

    public LeilaoDataBuilder na(Ordem ordem){
        this.ordem = ordem;

        return this;
    }

    public LeilaoDataBuilder comNumeroLancesIgualA(int numeroLances){
        this.numeroLances = numeroLances;

        return this;
    }

    public static LeilaoDataBuilder builder(){
        return new LeilaoDataBuilder();
    }

    public Leilao build() {
        Leilao leilao = new Leilao(nomeLeilao);

        IntStream.range(0, numeroLances)
            .mapToObj(i -> new Lance(new Usuario("Fulano " + i), ordem.proximoNumero(i)))
            .forEach(l -> leilao.propoe(l));

        return leilao;
    }

    public enum Ordem{
        CRESCENTE(1,1), DECRESCENTE(999_999, -1);

        private int numeroBase;
        private int numeroSinal;

        private Ordem(int numeroBase, int numeroSinal) {
            this.numeroBase = numeroBase;
            this.numeroSinal = numeroSinal;
        }

        public int proximoNumero(int numeroIteracao) {
            return numeroBase + (numeroIteracao * numeroSinal);
        }
    }
}

package br.com.caelum.leilao.dominio;

import java.util.Objects;

public class Lance implements Comparable<Lance> {
    private double valor;
    private Usuario usuario;

    public Lance(Usuario usuario, double valor) {
        this.usuario = usuario;
        this.valor = valor;
    }

    public Usuario getUsuario() {
        return usuario;
    }

    public double getValor() {
        return valor;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        long temp;
        temp = Double.doubleToLongBits(valor);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Lance other = (Lance) obj;
        if (Double.doubleToLongBits(valor) != Double.doubleToLongBits(other.valor))
            return false;
        return true;
    }

    @Override
    public int compareTo(Lance outroLance) {
        Objects.requireNonNull(outroLance);

        return (int) Math.signum(valor - outroLance.getValor());
    }

    @Override
    public String toString() {
        return String.format("Lance [valor=%s, usuario=%s]", valor, usuario);
    }
}

package br.com.caelum.leilao.dominio;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.google.common.collect.Lists;

public class Leilao {
    private String descricao;
    private List<Lance> lances;

    public Leilao(String descricao) {
        this.descricao = descricao;
        this.lances = Lists.newArrayList();
    }

    public void propoe(Lance lance) {        
        lances.add(lance);

        Collections.sort(lances);
    }

    public String getDescricao() {
        return descricao;
    }

    public List<Lance> getTresMaioresLances() {
        int indiceMinimoTresMaioresLances = lances.size() - 3 >= 0 ? lances.size() - 3 : lances.size() - 1;  
        List<Lance> tresMaioresLances = lances.subList(indiceMinimoTresMaioresLances,lances.size());
        Collections.sort(tresMaioresLances, Comparator.comparingDouble(Lance::getValor).reversed());

        return tresMaioresLances;
    }

    public List<Lance> getLances() {
        return lances;
    }

    @Override
    public String toString() {
        return String.format("Leilao [descricao=%s, lances=%s]", descricao, lances);
    }
}
3 respostas

Realmente tem muito código :). A parte diferente é o método privado que gera o objeto para ser testado? Se for, achei que ficou legal.

Isso o método privado cria o objeto pronto para o teste com a ajuda de um dataBuilder.

Dei uma melhorada nele, para gerar de forma automática o leilao com lances ou fornecendo valores dos respectivos lances. A classe de teste praticamente só tem Asserts com métodos privados bem pequenos que ajudam na criação do objeto.

package br.com.caelum.leilao.servico;

import static org.hamcrest.Matchers.closeTo;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.util.Collections;
import java.util.List;

import org.junit.Test;

import com.google.common.collect.Lists;

import br.com.caelum.leilao.dominio.Leilao;
import br.com.caelum.leilao.dominio.LeilaoDataBuilder;
import br.com.caelum.leilao.dominio.LeilaoDataBuilder.Ordem;

@SuppressWarnings("unchecked")
public class AvaliadorTest {

    @Test
    public void deveRetornarValoresEmOrdemCrescenteDeLances(){
        Avaliador avaliador = criarAvaliadorComLeilaoTendoLancesAutomaticosEmOrdem(5, Ordem.CRESCENTE);

        assertThat(avaliador.getMaiorLance(), closeTo(5, 0.0001));
        assertThat(avaliador.getMenorLance(), closeTo(1, 0.0001));
        assertThat(avaliador.getLanceMedio(), closeTo(3, 0.0001));
    }

    @Test
    public void deveRetornarValoresEmOrdemDecrescenteDeLances(){
        Avaliador avaliador = criarAvaliadorComLeilaoTendoLancesAutomaticosEmOrdem(5, Ordem.DECRESCENTE);

        assertThat(avaliador.getMaiorLance(), closeTo(999_999, 0.0001));
        assertThat(avaliador.getMenorLance(), closeTo(999_995, 0.0001));
        assertThat(avaliador.getLanceMedio(), closeTo(999_997, 0.0001));
    }

    @Test
    public void deveRetornarValoresRandomicoDeLances(){
        Avaliador avaliador = criarAvaliadorComLeilaoComLances(Lists.newArrayList(200.0, 450.0, 120.0, 700.0, 630.0, 230.0));

        assertThat(avaliador.getMaiorLance(), closeTo(700, 0.0001));
        assertThat(avaliador.getMenorLance(), closeTo(120, 0.0001));
        assertThat(avaliador.getLanceMedio(), closeTo(388.3333, 0.0001));
    }

    @Test
    public void deveRetornarUnicoValorDoLanceParaTodasEstatisticas(){
        Avaliador avaliador = criarAvaliadorComLeilaoComLances(Lists.newArrayList(200.0));

        assertThat(avaliador.getMaiorLance(), closeTo(200, 0.0001));
        assertThat(avaliador.getMenorLance(), closeTo(200, 0.0001));
        assertThat(avaliador.getLanceMedio(), closeTo(200, 0.0001));
    }

    @Test
    public void deveRetornarValorZeroParaTodasEstatisticasComNenhumLance(){
        Avaliador avaliador = criarAvaliadorComLeilaoComLances(Collections.EMPTY_LIST);

        assertThat(avaliador.getMaiorLance(), closeTo(0, 0.0001));
        assertThat(avaliador.getMenorLance(), closeTo(0, 0.0001));
        assertThat(avaliador.getLanceMedio(), closeTo(0, 0.0001));
    }

    @Test
    public void deveRetornarTresMaioresEmOrdemDecrescenteDeValoresComMuitosLances(){
        Avaliador avaliador = criarAvaliadorComLeilaoTendoLancesAutomaticosEmOrdem(5, Ordem.CRESCENTE);

        assertThat(avaliador.getTresMaioresLances(), hasSize(3));
        assertThat(avaliador.getTresMaioresLances(), contains(hasProperty("valor", is(5.0)), hasProperty("valor", is(4.0)), hasProperty("valor", is(3.0))));
    }

    @Test
    public void deveRetornarTodosOrdenadosEmOrdemDecrescenteComApenasDoisLances(){
        Avaliador avaliador = criarAvaliadorComLeilaoTendoLancesAutomaticosEmOrdem(2, Ordem.DECRESCENTE);

        assertThat(avaliador.getTresMaioresLances(), hasSize(2));
        assertThat(avaliador.getTresMaioresLances(), contains(hasProperty("valor", is(999_999.0)),hasProperty("valor", is(999_998.0))));
    }

    @Test
    public void deveRetornarListaVaziaParaTresMaioresLancesQuandoNaoHaLance(){
        Avaliador avaliador = criarAvaliadorComLeilaoTendoLancesAutomaticosEmOrdem(0, Ordem.CRESCENTE);

        assertThat(avaliador.getTresMaioresLances(), hasSize(0));
    }

    private Avaliador criarAvaliadorComLeilaoComLances(List<Double> valorLances) {
        LeilaoDataBuilder leilaoBuilder = LeilaoDataBuilder.builder();
        valorLances.forEach(leilaoBuilder::comLanceDe);

        return criarAvaliador(leilaoBuilder.build());
    }

    private Avaliador criarAvaliadorComLeilaoTendoLancesAutomaticosEmOrdem(int lances, Ordem ordem) {
        Leilao leilao = LeilaoDataBuilder.builder()
                .comLancesAutomaticosNaOrdem(lances, ordem)    
                .build();

        return criarAvaliador(leilao);
    }

    private Avaliador criarAvaliador(Leilao leilao) {
        Avaliador avaliador = new Avaliador();
        avaliador.avaliar(leilao);

        return avaliador;
    }
}

package br.com.caelum.leilao.dominio;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

public class LeilaoDataBuilder {
    private String nomeLeilao = "Playstation 4";
    private Ordem ordem;
    private int numeroLances;
    private List<Double> valoresLance = new ArrayList<>(); 

    public LeilaoDataBuilder com(String nome){
        this.nomeLeilao = nome;

        return this;
    }

    public LeilaoDataBuilder comLancesAutomaticosNaOrdem(int numeroLances, Ordem ordem){
        this.numeroLances = numeroLances;
        this.ordem = ordem;

        return this;
    }

    public LeilaoDataBuilder comLanceDe(double valorLance){
        this.valoresLance.add(valorLance);

        return this;
    }

    public static LeilaoDataBuilder builder(){
        return new LeilaoDataBuilder();
    }

    public Leilao build() {
        Leilao leilao = new Leilao(nomeLeilao);

        if(!valoresLance.isEmpty()){
            numeroLances = valoresLance.size();
        }

        IntStream.range(0, numeroLances)
            .mapToObj(i -> new Lance(new Usuario("Fulano " + i), getProximoNumero(i)))
            .forEach(l -> leilao.propoe(l));

        return leilao;
    }

    private double getProximoNumero(int i) {
        return ordem!=null ? ordem.proximoNumero(i) : valoresLance.get(i);
    }

    public enum Ordem{
        CRESCENTE(1,1), DECRESCENTE(999_999, -1);

        private int numeroBase;
        private int numeroSinal;

        private Ordem(int numeroBase, int numeroSinal) {
            this.numeroBase = numeroBase;
            this.numeroSinal = numeroSinal;
        }

        public int proximoNumero(int numeroIteracao) {
            return numeroBase + (numeroIteracao * numeroSinal);
        }
    }
}

Comparando com o teste padrão da resposta com apenas 3 testes

@Test
    public void deveEncontrarOsTresMaioresLances() {
        Usuario joao = new Usuario("João");
        Usuario maria = new Usuario("Maria");
        Leilao leilao = new Leilao("Playstation 3 Novo");

        leilao.propoe(new Lance(joao, 100.0));
        leilao.propoe(new Lance(maria, 200.0));
        leilao.propoe(new Lance(joao, 300.0));
        leilao.propoe(new Lance(maria, 400.0));

        Avaliador leiloeiro = new Avaliador();
        leiloeiro.avalia(leilao);

        List<Lance> maiores = leiloeiro.getTresMaiores();

        assertEquals(3, maiores.size());
        assertEquals(400, maiores.get(0).getValor(), 0.00001);
        assertEquals(300, maiores.get(1).getValor(), 0.00001);
        assertEquals(200, maiores.get(2).getValor(), 0.00001);
    }

    @Test
    public void deveDevolverTodosLancesCasoNaoHajaNoMinimo3() {
        Usuario joao = new Usuario("João");
        Usuario maria = new Usuario("Maria");
        Leilao leilao = new Leilao("Playstation 3 Novo");

        leilao.propoe(new Lance(joao, 100.0));
        leilao.propoe(new Lance(maria, 200.0));

        Avaliador leiloeiro = new Avaliador();
        leiloeiro.avalia(leilao);

        List<Lance> maiores = leiloeiro.getTresMaiores();

        assertEquals(2, maiores.size());
        assertEquals(200, maiores.get(0).getValor(), 0.00001);
        assertEquals(100, maiores.get(1).getValor(), 0.00001);
    }

    @Test
    public void deveDevolverListaVaziaCasoNaoHajaLances() {
        Leilao leilao = new Leilao("Playstation 3 Novo");

        Avaliador leiloeiro = new Avaliador();
        leiloeiro.avalia(leilao);

        List<Lance> maiores = leiloeiro.getTresMaiores();

        assertEquals(0, maiores.size());
    }
solução!

Ficou legal sim, mandou bem.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software