← Voltar ao blog

Gerador de CEP para testes: formato, algoritmo e estados cobertos

·9 min de leitura

CEP não é só um número de 8 dígitos. É um código com estrutura hierárquica definida pelos Correios, onde cada faixa de dígitos carrega informação geográfica. Gerar um CEP aleatório para teste e esperar que ele passe num formulário real é a receita para falsos positivos em QA — o campo aceita o dado, mas a integração com ViaCEP, o checkout ou o cálculo de frete quebra em produção. Este artigo explica a estrutura do CEP, como gerar valores geograficamente plausíveis e como o FakeForge resolve isso para os 10 estados com maior volume de testes.

CEP é um código estruturado, não aleatório

Anatomia dos 8 dígitos (faixa regional + setor + sufixo)

O CEP tem formato NNNNN-NNN. Os Correios dividem os 8 dígitos em três níveis:

  • Dígitos 1-5 (faixa de distribuição): identificam a região de entrega. Os dois primeiros dígitos definem a grande região do país, e os três seguintes afunilam até o município ou distrito postal.
  • Dígito 6 (setor): subdivide a faixa dentro da cidade.
  • Dígitos 7-8 (sufixo): identificam o logradouro específico dentro do setor.

Um CEP como 01310-100 é a Avenida Paulista em São Paulo. O 01 indica a capital paulista, o 3 aponta para o setor Centro, e o sufixo 100 define o trecho exato da avenida.

Como os Correios atribuem faixas por estado e por cidade

Os Correios atribuem faixas por estado em blocos contíguos, definidos administrativamente. São Paulo começa em 01000-000 por ter o maior volume de logradouros. Estados menores recebem faixas mais estreitas. Essa atribuição não segue nenhum algoritmo público e padrão — é resultado de decisões administrativas históricas dos Correios, com a tabela oficial disponível no site ECT.

Faixas de CEP por estado: tabela de referência

Cobertura das 27 UFs com prefixos iniciais e finais

A tabela abaixo lista os prefixos (primeiros dois dígitos) por UF. Alguns estados compartilham prefixo — nesses casos, o terceiro dígito diferencia.

UFPrefixo inicialPrefixo finalExemplo de capital
SP01000-00019999-999São Paulo
RJ20000-00028999-999Rio de Janeiro
ES29000-00029999-999Vitória
MG30000-00039999-999Belo Horizonte
BA40000-00048999-999Salvador
SE49000-00049999-999Aracaju
PE50000-00056999-999Recife
AL57000-00057999-999Maceió
PB58000-00058999-999João Pessoa
RN59000-00059999-999Natal
CE60000-00063999-999Fortaleza
PI64000-00064999-999Teresina
MA65000-00065999-999São Luís
PA66000-00068899-999Belém
AP68900-00068999-999Macapá
AM69000-00069299-999Manaus
RR69300-00069399-999Boa Vista
AC69900-00069999-999Rio Branco
DF70000-00073699-999Brasília
GO73700-00076799-999Goiânia
TO77000-00077999-999Palmas
MS79000-00079999-999Campo Grande
MT78000-00078899-999Cuiabá
RO78900-00078999-999Porto Velho
PR80000-00087999-999Curitiba
SC88000-00089999-999Florianópolis
RS90000-00099999-999Porto Alegre

Por que CEPs de regiões distintas têm estruturas diferentes

A faixa de SP vai de 01000-000 a 19999-999 — quase 19 milhões de CEPs possíveis para cobrir o estado mais populoso. O AM vai de 69000-000 a 69299-999 — cerca de 300 mil CEPs para um estado com distribuição urbana concentrada em Manaus. Essa assimetria reflete densidade populacional e volume de logradouros cadastrados. Para testes que envolvem cálculo de frete por região, ignorar essas faixas gera dados que nunca existiriam na base dos Correios.

O que torna um CEP "válido" para fins de teste

Formato obrigatório (NNNNN-NNN) e regras de comprimento

O formato NNNNN-NNN é obrigatório. Oito dígitos numéricos, hífen obrigatório na posição 6. Sistemas legados às vezes aceitam NNNNNNNN sem hífen, mas qualquer API pública dos Correios ou serviço como ViaCEP rejeita o formato sem separador. Validação de comprimento é necessária, mas não suficiente.

Correlação obrigatória: CEP + cidade + estado + bairro precisam ser coerentes

Um CEP 01310-100 que vem acompanhado de cidade: Curitiba, estado: PR vai falhar em qualquer integração que consulte o CEP numa API de endereço. A cidade e o estado precisam bater com a faixa do CEP. Para fixtures de banco de dados, isso significa que gerar CEP e cidade independentemente cria dados inconsistentes que causam regressão em testes de integração.

Diferença entre CEP sintaticamente correto e CEP geograficamente plausível

99999-999 passa qualquer validação de formato. Não existe na base dos Correios. 01000-000 também passa a validação e é o CEP do Largo do Paissandu em São Paulo — existe de verdade. Para a maioria dos testes, um CEP dentro da faixa correta da UF é suficiente. Para testes de integração com ViaCEP ou APIs de frete, o CEP precisa existir na base.

DICA: Para testes unitários de validação de formulário, um CEP dentro da faixa da UF é suficiente. Para testes de integração que consultam APIs externas, use CEPs reais conhecidos como constantes de fixture — não tente gerá-los sinteticamente.

Abordagem naive e por que ela falha em testes reais

Gerar string aleatória de 8 dígitos: o que quebra downstream

// Não faça isso
const cep = Math.floor(Math.random() * 100000000).toString().padStart(8, '0');

Esse trecho produz CEPs como 00000000 ou 99999999, que não pertencem a nenhum estado. Em produção, o campo de formulário pode aceitar o valor, mas o cálculo de frete retorna erro, o preenchimento automático de endereço falha e o log de erro não indica onde está o problema — porque o dado passou na validação de formato.

Casos concretos: campo de endereço, integração com ViaCEP, checkout de e-commerce

  • Campo de endereço com autopreenchimento: consulta o ViaCEP com o CEP do fixture. CEP fora de faixa retorna 404. O teste falha com mensagem de erro de rede, não de lógica de negócio.
  • Checkout de e-commerce: calculadoras de frete como Melhor Envio usam o CEP de destino para determinar prazo e valor. Um CEP 00000000 retorna erro de UF desconhecida.
  • Cadastro de fornecedor com CNPJ: o endereço do CNPJ precisa ter CEP coerente com o estado do CNPJ. Um CNPJ com inscrição estadual de SP acompanhado de CEP 90000-000 (RS) levanta flag em validações de consistência.

Como implementar um gerador de CEP correlacionado

Estrutura de dados mínima: tabela de faixas por UF

interface UFRange {
  uf: string;
  city: string;
  min: number;
  max: number;
  neighborhoods: string[];
}

const UF_RANGES: UFRange[] = [
  {
    uf: 'SP',
    city: 'São Paulo',
    min: 1000000,
    max: 5999999,
    neighborhoods: ['Centro', 'Pinheiros', 'Vila Madalena', 'Moema', 'Santana'],
  },
  {
    uf: 'RJ',
    city: 'Rio de Janeiro',
    min: 20000000,
    max: 23799999,
    neighborhoods: ['Centro', 'Copacabana', 'Ipanema', 'Tijuca', 'Botafogo'],
  },
  {
    uf: 'PR',
    city: 'Curitiba',
    min: 80000000,
    max: 82999999,
    neighborhoods: ['Centro', 'Batel', 'Água Verde', 'Portão', 'Boa Vista'],
  },
];

Sorteio dentro da faixa + composição de cidade e bairro coerentes

function generateCEP(uf: string): string {
  const range = UF_RANGES.find((r) => r.uf === uf);
  if (!range) throw new Error(`UF não suportada: ${uf}`);

  const raw = Math.floor(Math.random() * (range.max - range.min + 1)) + range.min;
  const digits = raw.toString().padStart(8, '0');
  return `${digits.slice(0, 5)}-${digits.slice(5)}`;
}

Exemplo de implementação em TypeScript

interface Address {
  cep: string;
  city: string;
  state: string;
  neighborhood: string;
}

function generateAddress(uf: string): Address {
  const range = UF_RANGES.find((r) => r.uf === uf);
  if (!range) throw new Error(`UF não suportada: ${uf}`);

  const cep = generateCEP(uf);
  const neighborhood =
    range.neighborhoods[Math.floor(Math.random() * range.neighborhoods.length)];

  return {
    cep,
    city: range.city,
    state: range.uf,
    neighborhood,
  };
}

// Uso
const address = generateAddress('SP');
// { cep: '03421-780', city: 'São Paulo', state: 'SP', neighborhood: 'Moema' }

Geração em volume: seed scripts e fixtures

Gerar N endereços distintos para popular banco de dados de teste

Para popular uma tabela de clientes de teste com endereços distribuídos entre estados, a abordagem mais simples é iterar sobre as UFs disponíveis em round-robin:

function generateAddresses(count: number): Address[] {
  const ufs = UF_RANGES.map((r) => r.uf);
  return Array.from({ length: count }, (_, i) =>
    generateAddress(ufs[i % ufs.length])
  );
}

Export SQL com CREATE TABLE pronto para rodar em CI

O FakeForge gera o bloco SQL completo, incluindo CREATE TABLE e os INSERT correspondentes. O export está disponível via API com format=sql. O resultado é pronto para rodar em PostgreSQL, MySQL ou SQLite sem ajuste manual.

-- Generated by FakeForge BR -- free Brazilian test data
-- https://fakeforge.com.br
-- Generated at: 2026-06-04T10:00:00Z
-- License: CC0 (public domain test data)

CREATE TABLE IF NOT EXISTS enderecos (
  id SERIAL PRIMARY KEY,
  cep VARCHAR(9) NOT NULL,
  cidade VARCHAR(100) NOT NULL,
  estado CHAR(2) NOT NULL,
  bairro VARCHAR(100) NOT NULL
);

INSERT INTO enderecos (cep, cidade, estado, bairro) VALUES
('01310-100', 'São Paulo', 'SP', 'Centro'),
('80010-020', 'Curitiba', 'PR', 'Batel'),
('90010-150', 'Porto Alegre', 'RS', 'Centro Histórico');

Integração com a API do FakeForge

Endpoint /api/generate?type=cep&quantity=50&format=json

O endpoint REST aceita type=cep, quantity de 1 a 10.000 e format como json, csv ou sql. Sem autenticação para até 100 chamadas por dia no plano gratuito. Acima disso, os planos pagos desbloqueiam volume maior e SLA de resposta.

Parâmetros de formato: json, csv, sql

curl "https://fakeforge.com.br/api/generate?type=cep&quantity=10&format=csv"

A resposta CSV inclui cabeçalho com os nomes das colunas. O formato SQL inclui o CREATE TABLE seguido dos INSERT. O formato JSON retorna um array de objetos com os campos cep, cidade, estado e bairro.

Exemplo de chamada com fetch e com curl

interface CEPResponse {
  _meta: {
    source: string;
    url: string;
    generated_at: string;
    license: string;
  };
  type: string;
  quantity: number;
  data: Array<{
    cep: string;
    cidade: string;
    estado: string;
    bairro: string;
  }>;
}

async function fetchCEPs(quantity: number): Promise<CEPResponse> {
  const response = await fetch(
    `https://fakeforge.com.br/api/generate?type=cep&quantity=${quantity}&format=json`
  );
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return response.json() as Promise<CEPResponse>;
}

// Uso em setup de teste
const { data: enderecos } = await fetchCEPs(50);

A documentação completa da API, incluindo todos os tipos e parâmetros disponíveis, está em /docs.

Considerações de LGPD ao usar CEPs em testes

CEP não é dado pessoal isolado, mas pode ser quando combinado

O CEP sozinho não identifica uma pessoa. Combinado com nome, CPF ou data de nascimento, passa a integrar um conjunto de dados pessoais conforme LGPD Art. 5º, I. Um banco de dados de teste com cpf + nome + endereço real é um conjunto de dados pessoais, mesmo que seja para fins internos.

Ambientes de teste devem usar dados sintéticos, não dumps de produção

O LGPD Art. 46 exige medidas técnicas e administrativas para proteger dados pessoais contra acessos não autorizados. Um dump de produção usado em ambiente de desenvolvimento — com acesso menos restrito, sem criptografia completa, compartilhado entre membros da equipe — falha nesse requisito. A ANPD já indicou, em guias de boas práticas, que a anonimização ou síntese de dados para ambientes de teste é a abordagem adequada.

Por que dados gerados sinteticamente eliminam o risco de exposição

Dados gerados pelo FakeForge não têm correspondência com pessoas reais. O CEP 03421-780 gerado sinteticamente não pertence a nenhum titular identificável. Mesmo que o banco de dados de teste vaze, não há dado pessoal exposto — porque nenhum dado pessoal foi inserido. Isso elimina a necessidade de anonimização post-hoc e simplifica o processo de resposta a incidentes.

AVISO: Usar dados reais de clientes em ambiente de staging ou desenvolvimento é infração ao Art. 46 da LGPD e sujeita a multa de até 2% do faturamento, limitada a R$ 50 milhões por infração, conforme Art. 52.

Estados e capitais cobertos no FakeForge

As 10 capitais com dados de bairro curados

O gerador de CEP do FakeForge tem dados de bairro curados para 10 capitais: São Paulo, Rio de Janeiro, Belo Horizonte, Porto Alegre, Salvador, Fortaleza, Recife, Manaus, Brasília e Curitiba. Para essas cidades, o endereço gerado inclui bairros reais com nomes corretos e CEP dentro da faixa correta da capital. As páginas específicas, como /gerador-cep/sao-paulo e /gerador-cep/rio-de-janeiro, mostram exemplos com os bairros disponíveis.

Cobertura das demais UFs por faixa de prefixo sem dados de bairro específicos

Para os 17 estados restantes, o FakeForge gera CEPs dentro da faixa correta da UF com cidade capital e estado coerentes, mas sem lista curada de bairros. O bairro retornado é genérico ("Centro") ou omitido, dependendo do contexto. Isso é suficiente para a maioria dos testes de formulário e integração que só validam estado e cidade.

Como o projeto define o equilíbrio entre cobertura e precisão geográfica

Manter dados de bairro curados para 27 estados exige atualização contínua, porque os Correios alteram faixas de CEP com frequência. O recorte das 10 capitais cobre mais de 60% dos testes típicos de sistemas BR, onde o foco é nos grandes centros urbanos. Para casos que precisam de cobertura completa de bairros por estado, a integração com a API dos Correios ou com o ViaCEP em ambiente de teste controlado é a abordagem mais precisa.

Para gerar uma pessoa completa com endereço correlacionado — nome, CPF, telefone e CEP do mesmo estado — ou uma empresa com CNPJ e endereço coerente, os geradores compostos do FakeForge fazem esse trabalho de correlação automaticamente.

Resumo

  • CEP tem estrutura hierárquica definida pelos Correios. Gerar 8 dígitos aleatórios produz dados fora de qualquer faixa de UF e quebra integrações downstream.
  • Cada UF tem faixas de prefixo específicas. A tabela neste artigo cobre as 27 UFs com os limites inicial e final de cada estado.
  • Um CEP válido para teste precisa de correlação: CEP + cidade + estado + bairro devem ser coerentes entre si, não gerados independentemente.
  • Use CEPs sintéticos dentro da faixa correta da UF para testes unitários e de formulário. Para testes de integração com ViaCEP ou APIs de frete, prefira CEPs reais conhecidos como constantes de fixture.
  • Dados sintéticos eliminam o risco de LGPD em ambientes de teste. Dumps de produção com CEP + CPF + nome constituem conjunto de dados pessoais sujeito ao Art. 46.
  • O FakeForge cobre 10 capitais com bairros curados e todas as 27 UFs por faixa de prefixo, com export via API em JSON, CSV e SQL com CREATE TABLE pronto para CI.

Perguntas frequentes

Como validar se um CEP gerado está dentro da faixa correta sem chamar API?+

Precisa estar entre min e max da UF. Exemplo: SP [01000000, 19999999]. Extraia os 2 primeiros dígitos como número inteiro, compare com a tabela de ranges do artigo. Não confunda com validação de formato (NNNNN-NNN) — essa só garante sintaxe, não faixa. Para testes unitários, basta isso. Para integração, CEP real é mais seguro.

Posso usar qualquer CEP dentro da faixa de São Paulo em um teste de e-commerce?+

Para validação de formato, sim. Para checkout com cálculo de frete real, não — a maioria das APIs (Melhor Envio, Sedex) rejeita CEPs inexistentes. Use CEPs reais conhecidos como constantes (`01310-100` = Avenida Paulista). Gerar sintético serve para testes unitários, não para integração com terceiros.

Como estruturar fixtures de teste (CPF + nome + CEP) sem violar LGPD?+

Gere tudo sinteticamente com o FakeForge — CPF, nome e CEP não correspondem a pessoas reais. Não use dumps de produção nem dados de clientes reais. Dados sintéticos sem correspondência à realidade não são "dados pessoais" conforme LGPD Art. 5º, eliminando risco de infração ao Art. 46.

Os CEPs gerados pelo FakeForge existem realmente nos Correios?+

Não. São sinteticamente válidos dentro da faixa de cada UF, mas não correspondem a logradouros reais cadastrados nos Correios. Para testes unitários de validação de formato, é suficiente. Para testes de integração com ViaCEP que consultam a base real, use CEPs conhecidos ou mock a resposta da API.

Como debugar se o teste falha por CEP inválido ou por lógica bugada?+

Valide o CEP isoladamente contra a faixa da UF antes de rodar o teste. Se passa nessa validação mas falha em integração com ViaCEP, o problema é a lógica ou a API mockada, não o formato. Log o CEP, cidade, estado recebidos e compare com a resposta esperada — identifica mismatch entre geração e integração rapidamente.