O Gerador De CPF O Gerador De CPF

Gerar CPF em Spring Boot: Service Bean com Testes JUnit 5

Em aplicações Spring Boot, poder gerar CPF programaticamente dentro da própria aplicação simplifica test fixtures, ambientes de desenvolvimento e ferramentas internas. Este artigo implementa o algoritmo de módulo 11 como Service bean reutilizável, com REST endpoint para geração via HTTP e testes automatizados.

Service

package com.example.service;

import org.springframework.stereotype.Service;
import java.util.Random;

@Service
public class CpfGeneratorService {

    private final Random random = new Random();

    public String generate() {
        int[] digits = new int[11];

        for (int i = 0; i < 9; i++) {
            digits[i] = random.nextInt(10);
        }

        // Primeiro dígito verificador
        int sum = 0;
        for (int i = 0; i < 9; i++) {
            sum += digits[i] * (10 - i);
        }
        int r = sum % 11;
        digits[9] = r < 2 ? 0 : 11 - r;

        // Segundo dígito verificador
        sum = 0;
        for (int i = 0; i < 10; i++) {
            sum += digits[i] * (11 - i);
        }
        r = sum % 11;
        digits[10] = r < 2 ? 0 : 11 - r;

        StringBuilder sb = new StringBuilder(11);
        for (int d : digits) {
            sb.append(d);
        }
        return sb.toString();
    }

    public boolean validate(String cpf) {
        String cleaned = cpf.replaceAll("[^\\d]", "");

        if (cleaned.length() != 11) return false;
        if (cleaned.chars().distinct().count() == 1) return false;

        int[] digits = new int[11];
        for (int i = 0; i < 11; i++) {
            digits[i] = cleaned.charAt(i) - '0';
        }

        for (int t = 9; t < 11; t++) {
            int sum = 0;
            for (int c = 0; c < t; c++) {
                sum += digits[c] * ((t + 1) - c);
            }
            int r = sum % 11;
            int expected = r < 2 ? 0 : 11 - r;
            if (digits[t] != expected) return false;
        }

        return true;
    }
}

REST Endpoint

package com.example.controller;

import com.example.service.CpfGeneratorService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.IntStream;

@RestController
@RequestMapping("/api/cpf")
public class CpfGeneratorController {

    private final CpfGeneratorService cpfGeneratorService;

    public CpfGeneratorController(CpfGeneratorService cpfGeneratorService) {
        this.cpfGeneratorService = cpfGeneratorService;
    }

    @GetMapping("/generate")
    public List<String> generate(@RequestParam(defaultValue = "1") int count) {
        int safeCount = Math.min(Math.max(count, 1), 100);
        return IntStream.range(0, safeCount)
                .mapToObj(i -> cpfGeneratorService.generate())
                .toList();
    }
}

Teste de integração

package com.example.service;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class CpfGeneratorServiceIntegrationTest {

    @Autowired
    private CpfGeneratorService cpfGeneratorService;

    @Test
    void serviceBeanDeveGerarCpfValido() {
        String cpf = cpfGeneratorService.generate();
        assertNotNull(cpf);
        assertEquals(11, cpf.length());
        assertTrue(cpfGeneratorService.validate(cpf));
    }

    @Test
    void serviceBeanDeveGerarCpfsDiferentes() {
        String cpf1 = cpfGeneratorService.generate();
        String cpf2 = cpfGeneratorService.generate();
        String cpf3 = cpfGeneratorService.generate();
        assertFalse(cpf1.equals(cpf2) && cpf2.equals(cpf3),
                "Três CPFs gerados consecutivamente não devem ser todos iguais");
    }

    @Test
    void serviceBeanDeveValidarCpfComMascara() {
        String cpf = cpfGeneratorService.generate();
        String formatted = cpf.substring(0, 3) + "." + cpf.substring(3, 6) + "."
                + cpf.substring(6, 9) + "-" + cpf.substring(9);
        assertTrue(cpfGeneratorService.validate(formatted));
    }
}

Análise do código

O CpfGeneratorService é anotado com @Service, o que permite ao Spring gerenciá-lo como bean singleton e injetá-lo em qualquer componente via construtor. O método generate() cria um array de 11 posições, preenche as nove primeiras com dígitos aleatórios via random.nextInt(10) e calcula os dois verificadores pela fórmula do módulo 11. O método auxiliar validate() permite confirmar a integridade do CPF gerado sem depender de biblioteca externa.

O CpfGeneratorController expõe um endpoint GET /api/cpf/generate que aceita um parâmetro opcional count para geração em lote. O valor é limitado entre 1 e 100 com Math.min e Math.max para evitar abuso. A injeção de dependência via construtor segue a prática recomendada do Spring — sem @Autowired no campo, facilitando a criação de testes unitários com mocks.

O teste de integração usa @SpringBootTest para subir o contexto completo do Spring e injeta o service com @Autowired. Isso garante que a configuração do bean, a injeção de dependência e o ciclo de vida funcionam corretamente no ambiente real da aplicação. Os três métodos de teste cobrem geração válida, aleatoriedade e suporte a CPF formatado com máscara.

Testes unitários

package com.example.service;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CpfGeneratorServiceTest {

    private final CpfGeneratorService service = new CpfGeneratorService();

    @Test
    void geradoDeveTer11Digitos() {
        String cpf = service.generate();
        assertEquals(11, cpf.length());
        assertTrue(cpf.matches("\\d{11}"));
    }

    @Test
    void geradoDeveSerValido() {
        String cpf = service.generate();
        assertTrue(service.validate(cpf));
    }

    @Test
    void multiplosGeradosDevemDiferir() {
        String cpf1 = service.generate();
        String cpf2 = service.generate();
        String cpf3 = service.generate();
        assertFalse(cpf1.equals(cpf2) && cpf2.equals(cpf3),
                "Três CPFs gerados consecutivamente não devem ser todos iguais");
    }
}

O primeiro teste garante que o CPF tem exatamente 11 caracteres numéricos. O segundo confirma que o CPF gerado é reconhecido como válido pelo próprio validador do service. O terceiro gera três CPFs e verifica que não são todos idênticos, confirmando que a aleatoriedade funciona.


Veja também como validar CPF em Spring Boot com Bean Validation e anotação personalizada, ou volte à página inicial para gerar CPFs online.