Você quer começar a escrever testes. Mas o projeto que você trabalha tem muito código legado (ou seja sem teste) e por consequência existem muitos métodos longos.
Para piorar, você precisa alterar um método com, pelo menos, 100 linhas de código. E pior, dentro do método tem chamadas para outros métodos.
Você e sua equipe entendem que criar um teste unitário para este caso não vale a pena pois o custo para compreensão e criação do ambiente de testes (mocks e dados) são custosos.
E a solução sempre gira em torno de um teste mais custoso como teste de integração ou teste E2E. Ou simplesmente não cria testes.
E seu eu te disser que existe uma maneira simples e eficiente para testar somente a sua modificação?
Neste artigo, vamos explorar esta técnica passo a passo.
Exemplo de código#
package br.com.youready.article.d_2025_01_21.image1;
import java.util.ArrayList;
import java.util.List;
public class OrderProcessor {
public void processOrders(List<Order> orders) {
double totalRevenue = 0;
List<Order> failedOrders = new ArrayList<>();
System.out.println("Validating orders... ");
for (Order order : orders) {
if (order == null || order.items() == null || order.items().isEmpty()) {
assert order != null;
System.out.println("Invalid order: " + order.id());
failedOrders.add(order);
}
}
System.out.println("Processing valid orders... ");
for (Order order : orders) {
if (failedOrders.contains(order)) {
continue;
}
try {
double totalOrder = 0;
for (Item item : order.items()) {
totalOrder += item.price() * item.quantity();
}
totalRevenue += totalOrder;
System.out.println("Processed order: " + order.id() + " with total of " + totalOrder);
} catch (Exception e) {
System.err.println("Failed to process order: " + order.id());
failedOrders.add(order);
}
}
System.out.println("Order processing complete. Total revenue: " + totalRevenue);
}
}
O código acima valida as ordens e calcula o total de lucro que tivemos.
Mas um novo requisito chega para a equipe.
Como estamos chegando no black friday, você precisa aplicar um desconto de 25% para teclado e mouse.
Para isso, precisamos modificar a seguinte parte do código:
for (Item item : order.items()) {
totalOrder += item.price() * item.quantity();
}
totalRevenue += totalOrder;
Como testamos somente a alteração da parte comentada e ignoramos o resto do código já existente?
Ou seja, como criamos um teste unitário simples que não passe pelo método inteiro?
Primeiro passo: Extrair o trecho do código que será alterado#
Vamos extrair em um método o trecho do código comentado:
package br.com.youready.article.d_2025_01_21.image2;
import java.util.ArrayList;
import java.util.List;
public class OrderProcessor {
public void processOrders(List<Order> orders) {
double totalRevenue = 0;
List<Order> failedOrders = new ArrayList<>();
System.out.println("Validating orders...");
for (Order order : orders) {
if (order == null || order.items() == null || order.items().isEmpty()) {
assert order != null;
System.out.println("Invalid order: " + order.id());
failedOrders.add(order);
}
}
System.out.println("Processing valid orders...");
for (Order order : orders) {
if (failedOrders.contains(order)) {
continue;
}
try {
double totalOrder = getTotalOrder(order);
totalRevenue += totalOrder;
System.out.println("Processed order: " + order.id() + " with total of " + totalOrder);
} catch (Exception e) {
System.err.println("Failed to process order: " + order.id());
failedOrders.add(order);
}
}
System.out.println("Order processing complete. Total revenue: " + totalRevenue);
}
private static double getTotalOrder(Order order) {
double totalOrder = 0;
for (Item item : order.items()) {
totalOrder += item.price() * item.quantity();
}
return totalOrder;
}
}
Ou seja, o que precisamos testar fica mais claro, simples e conhecemos a dependência para testar este método:
- Order order
Legal!
Poderíamos tornar o método público, começar a testar e fazer a alteração.
É um caminho válido. Alguns podem argumentar que tornar um método privado para público para testes não é uma boa ideia, mas pelo bem da qualidade, eu prefiro torná-lo público.
Mas nesta situação específica podemos fazer melhor.
Segundo passo: Analisar o novo método e descobrir o melhor lugar para ele#
Se olharmos o método novo, percebemos que ele só depende do Order e as informações contidas nele. Estamos pedindo informações para o Order para calcular o total da ordem.
Quando temos um código que pede informações para o objeto, estamos quebrando o princípio Tell, Don’t Ask! Devemos dizer para o objeto do tipo Order calcular o total e não pedir informações para ele!
Uma nova refatoração poderia ser assim:
package br.com.youready.article.d_2025_01_21.image3;
import java.util.List;
record Order(Long id, List<Item> items) {
public double getTotal() {
double totalOrder = 0;
for (Item item : this.items()) {
totalOrder += item.price() * item.quantity();
}
return totalOrder;
}
}
Agora, além do trecho que vamos alterar ser público, ele está em um contexto muito mais focado.
Conseguimos sair do método longo e agora precisamos somente testar o Order#getTotal()!
E percebam que esse tipo de refatoração mais simples não precisa de testes, pois estamos somente movendo o código para um lugar novo.
Terceiro Passo: Criar o teste#
Agora sim vamos alterar o comportamento do sistema. Você pode aplicar TDD ou pode escrever o teste depois, mas a ideia principal é que está fácil de escrever o teste:
package br.com.youready.article.d_2025_01_21.image4;
import spock.lang.Specification
import static org.junit.jupiter.api.Assertions.assertEquals
class OrderSpec extends Specification {
def "Teclado e mouse deve ter um desconto de 25% no blackfriday"() {
setup:
Item teclado = new Item('Teclado', 100, 10)
Item mouse = new Item('Mouse', 50, 5)
List<String> itensComDesconto = [teclado.name(), mouse.name()]
Order order = new Order(1L, [teclado, mouse])
when:
def total = order.getTotal(itensComDesconto)
then:
def expectedTotal = teclado.price() * teclado.quantity() * 0.75
expectedTotal += mouse.price() * mouse.quantity() * 0.75
assertEquals(expectedTotal, total)
}
}
E podemos fazer a modificação necessária no código.
No exemplo acima só escrevi um teste mas o ideal é escrever mais casos de teste para o método novo. Ver se o comportamento funciona para quando a lista está vazia ou null, verificar se precisa normalizar antes de verificar se o item está na lista e etc.
Conclusão#
Neste artigo exploramos como criar um teste e verificar somente o trecho do código que precisamos alterar.
A ideia é bem simples: Só precisamos extrair ele para um novo método público, verificar as dependências, analisar se existe um lugar melhor e finalmente testar.
Se todos da equipe executarem estes passos todos os dias aos poucos, pode ter certeza que a manutenção, leitura e alteração do código vai ficando mais fácil e menos custoso.
Só precisamos ter disciplina.
Se tiver mais curiosidade sobre o assunto, pode falar comigo!
🥒🥒 Espero que tenham curtido e até o próximo artigo! 🥒🥒


