Como testar um método void com JUnit?

Olá,

Eu preciso testar um método, mas ele tem retorno void, como faço isso? Tentei dividir ele em dois métodos, um com algum retorno, e outro que imprimisse mas não consegui.

É uma classe Pizza, que adiciona os ingredientes em uma lista, e esse método contabiliza e imprime todos os ingredientes.

public void contaIngredientes() {
	for (String ingrediente : listaIngredientes) {
		int frequency = Collections.frequency(listaIngredientes, ingrediente);
		System.out.println(ingrediente + ": " + frequency);
	}
}

Quando existe mais de um ingrediente, o método contabiliza ele corretamente, mas imprime duas vezes o nome do ingrediente conforme a ordem que eles aparecem na lista. Vocês poderiam me ajudar a consertar isso também?

Como você está tentando testar esse método? Já tem algo escrito?

Testar métodos void é realmente algo mais complicado, pois depende do que o método tem que fazer. Nesse seu caso, ele vai contar os ingredientes. O bom é que o teste vai ajudar a identificar possíveis falhas no código escrito.

Nesse seu caso, seria mais fácil testar esse método se ele retornasse o total de ingredientes, isso iria fazer com que esse método fizesse mais sentido do que apenas imprimir algum valor no console com System.out.println.

Vc pode postar a classe completa para podermos entender melhor o objetivo dela? Vendo só esse método, a recomendação que faço é fazer com que ele retorne o total mesmo.

A classe completa é essa:

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

public class Pizza {

	static List<String> listaIngredientes = new ArrayList<>();
	double valorPizza = 0;
	static int quantidadeEstatica = 0;
	int quantidade = 0;
	
	public void adicionaIngrediente(String ingrediente) {
		listaIngredientes.add(ingrediente);
		quantidade++;
		contabilizaIngredientes();
	}

	public double getPreco() {
		if (quantidade <= 2) {
			valorPizza = 15;
			return valorPizza;
		}
		if(quantidade>=3 && quantidade<=5) {
			valorPizza = 20;
			return valorPizza;
		}
		else {
			valorPizza = 23;
			return valorPizza;
		}
	}
		
	public static void contabilizaIngredientes () {
		quantidadeEstatica++;	
	}	
	
	public void contaIngredientes () {
		
		for (String ingrediente : listaIngredientes) {
		int frequency = Collections.frequency(listaIngredientes, ingrediente);
		System.out.println(ingrediente + ": " + frequency);
		}
	}
		
	
	public static void zeraIngredientes() {
		quantidadeEstatica = 0;
		
	}

Eu tentei fazer o método retornar o frequency, em vez de imprimir ele na tela, só que daí ele só retorna o valor do primeiro item da lista. Aí eu tentei fazer ele retornar o frequency como uma lista, mas não consegui fazer isso, o código só dava erro. :frowning:

Pelo que estou entendendo, o método contaIngredientes deve contar o total por tipo de ingrediente dentro da lista de ingredientes. Se for isso mesmo, o retorno desse método seja um Map, pois vc terá um total para cada ingrediente que é usado na lista de ingredientes. Ex.:

List<String> ingredientes = new ArrayList<>();
ingredientes.add("ingredienteA");
ingredientes.add("ingredienteA");
ingredientes.add("ingredienteB");
ingredientes.add("ingredienteB");
ingredientes.add("ingredienteB");
ingredientes.add("ingredienteC");

System.out.println(Collections.frequency(ingredientes, "ingredienteA")); // 2
System.out.println(Collections.frequency(ingredientes, "ingredienteB")); // 3
System.out.println(Collections.frequency(ingredientes, "ingredienteC")); // 1

É isso mesmo que esse método contaIngredientes tem que fazer?

É isso mesmo que o método tem que fazer.
A sua sugestão é que ele retorne um Map? Daí esse Map daria para testar?
Você pode me mostrar como eu faço isso, por favor?

Classe Pizza com algumas modificações:

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Pizza {
    private static final List<String> ingredientes = new ArrayList<>();
    private double valorPizza = 0;

    public void adicionaIngrediente(String ingrediente) {
        ingredientes.add(ingrediente);
    }

    public double getPreco() {
        if (getTotalIngredientes() <= 2) {
            valorPizza = 15;
            return valorPizza;
        }
        
        if (getTotalIngredientes() >= 3 && getTotalIngredientes() <= 5) {
            valorPizza = 20;
            return valorPizza;
        } else {
            valorPizza = 23;
            return valorPizza;
        }
    }

    public Map<String, Integer> contarIngredientes() {
        Map<String, Integer> totalPorIngredientes = new HashMap<String, Integer>();
        
        for (String ingrediente : ingredientes) {
            int frequency = Collections.frequency(ingredientes, ingrediente);
            totalPorIngredientes.put(ingrediente, frequency);
        }
        
        return totalPorIngredientes;
    }
    
    public Integer getTotalIngredientes() {
        return ingredientes.size();
    }

    public void zerarIngredientes() {
        ingredientes.clear();
    }
}

Classe de Teste

import java.util.Map;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class PizzaTest {
    
    private Pizza fixture;
    
    @BeforeEach
    void setup() {
        fixture = new Pizza();
    }

    @Test
    public void devePossuirAQuantidadeCorretaDeIngredientes() {
        // Arrange
        fixture.adicionaIngrediente("ingredienteA");
        fixture.adicionaIngrediente("ingredienteA");
        fixture.adicionaIngrediente("ingredienteB");
        fixture.adicionaIngrediente("ingredienteB");
        fixture.adicionaIngrediente("ingredienteB");
        fixture.adicionaIngrediente("ingredienteC");
        
        // Act
        Map<String, Integer> actual = fixture.contarIngredientes();
        
        // Assert
        Assertions.assertEquals(2, actual.get("ingredienteA"));
        Assertions.assertEquals(3, actual.get("ingredienteB"));
        Assertions.assertEquals(1, actual.get("ingredienteC"));
    }

}

Caraca, Lucas! Valeu mesmo!
Estou fazendo um curso de Java, mas o curso é muito ruim, didática péssima, não ensina nada você a fazer as coisas e já pede pra entregar o exercício, aí estou perdidona. Mas, brigadão.

Aqui no GUJ tem muita gente que entende bastante de testes, sem falar que teste é algo fundamental para um bom desenvolvimento e, em muitas vezes, deixado de lado. Aqui no meu trabalho a galera força muito a questão de testes (seja unitário, integração ou até mesmo funcional, dependendo do caso). Mas teste unitário sempre é bom fazer.

Esse seu exemplo é muito para fazer uns testes bacanas. Qualquer dúvida, soh falar.

Qual curso vc está fazendo?

obs.: Nessa classe de teste, usei o JUnit na versão 5 ok. Se vc rodar ele com a versão 4 do JUnit, não vai funcionar.

Eu estou fazendo um que é o primeiro módulo de uma especialização do ITA, chama Orientação a Objetos com Java, fica na plataforma Coursera. Mas não gostei.
Você conhece algum curso bom?
Eu trabalho com suporte hoje, mas em fevereiro vou começar a trabalhar com desenvolvimento, aí tava querendo ir praticando bastante antes de entrar.

Uns cursos bem avaliados que vejo muito a galera comentar são esses:

Bacana, também comecei como suporte antes de ir para área de desenvolvimento.

Se vc for trabalhar com java, recomendo que dê uma olhada em Spring, que é amplamente utilizado hoje em dia).

Valeu pelas dicas, Lucas!

Marque depois a resposta que te ajudou como solução. Vlw!