Artigo Build·Desenvolvimento·13 min de leitura de leitura

Dados Fictícios para Testes de Software (2026): Ferramentas, Estratégias e LGPD

Dado fictício é a base de qualquer teste automatizado que não viola LGPD. Este guia cobre o porquê (lei + prática), ferramentas por linguagem, uso de factories e seed determinístico, cenários realistas e estratégias para manter ambiente de staging limpo e útil.

Vitor Morais

Por Vitor Morais

Fundador do MochaLabz ·

🎲

Gere CPFs em lote

Quantidade, formato e download em CSV — tudo no navegador, sem cadastro.

Usar gerador →

Dado fictício é pilar invisível de todo software que leva qualidade a sério: sem ele, seus testes automatizados não existem, sua demo tem dados de clientes reais expostos e seu staging vira risco de LGPD. O investimento em geração de dados fictícios é baixo (bibliotecas prontas, 5-10 linhas de código), o retorno é alto (testes confiáveis, conformidade, sanidade mental).

Este guia cobre os motivos práticos e legais para usar dados fictícios, bibliotecas padrão em JavaScript, Python, Ruby e Java, uso de factories para dados coerentes, seed determinístico para testes reproduzíveis em CI e estratégias para evitar que dados fictícios “vazem” para produção.

Por que dados fictícios: três razões fundamentais

1. LGPD (obrigatório)

Dado pessoal (CPF, nome, e-mail, telefone) em testes sem base legal viola a LGPD. Artigos 7 e 11 exigem finalidade específica. Uso para testes não se enquadra em nenhuma das 10 bases legais se o titular não consentiu. Multas vão até 2% do faturamento. Desde 2023, ANPD aplica multas reais. Dados fictícios eliminam o problema — documento matematicamente válido sem ser de pessoa real não é dado pessoal.

2. Vazamento de staging

Cenários reais: credencial de banco staging em commit do GitHub; backup acidental exposto em bucket S3 público; servidor de staging sem firewall. Se o banco tem CPFs reais, é vazamento. Se tem só fictícios, é zero problema.

3. Controle de cenários de teste

Teste precisa de dados previsíveis: “usuário com 3 pedidos vencidos”, “e-mail com acento no nome”, “data no ano 2038”. Dados reais têm distribuição natural que raramente cobre todos esses casos. Dados fictícios deixam você modelar cenários exatos.

Atenção

Dados reais ainda podem ser usados em testes se (1) foram anonimizados irreversivelmente (hash irreversível ou masking) E (2) base legal estiver documentada. Mas a complexidade e o risco raramente compensam vs gerar do zero com Faker.

Ferramentas por linguagem

JavaScript / TypeScript: Faker-js

npm install -D @faker-js/faker
import { faker } from "@faker-js/faker/locale/pt_BR"; // Pessoa completa const pessoa = { nome: faker.person.fullName(), cpf: faker.br.cpf(), email: faker.internet.email(), telefone: faker.phone.number(), dataNascimento: faker.date.birthdate(), endereco: { rua: faker.location.street(), numero: faker.number.int({ min: 1, max: 9999 }), bairro: faker.location.secondaryAddress(), cidade: faker.location.city(), estado: faker.location.state({ abbreviated: true }), cep: faker.location.zipCode("#####-###"), }, empresa: { nome: faker.company.name(), cnpj: faker.br.cnpj(), }, }; // Array de 1000 pessoas const pessoas = Array.from({ length: 1000 }, () => ({ nome: faker.person.fullName(), cpf: faker.br.cpf(), email: faker.internet.email(), }));

Python: Faker

pip install faker
from faker import Faker fake = Faker("pt_BR") # Pessoa completa pessoa = { "nome": fake.name(), "cpf": fake.cpf(), "email": fake.email(), "telefone": fake.phone_number(), "data_nascimento": fake.date_of_birth(), "endereco": { "rua": fake.street_name(), "numero": fake.random_int(1, 9999), "bairro": fake.bairro(), "cidade": fake.city(), "estado": fake.estado_sigla(), "cep": fake.postcode(), }, } # Lista de 1000 pessoas = [ { "nome": fake.name(), "cpf": fake.cpf(), "email": fake.email(), } for _ in range(1000) ]

Ruby: Faker gem

# Gemfile gem "faker" gem "factory_bot_rails" # Uso require "faker" Faker::Config.locale = :"pt-BR" Faker::Name.name # "João da Silva" Faker::CPF.number # "14339725095" Faker::CNPJ.number # "62030781000162" Faker::Internet.email # "joao@exemplo.com" Faker::PhoneNumber.cell_phone # "(11) 98765-4321" Faker::Address.city # "São Paulo" Faker::Company.name # "Empresa X LTDA"

Java: JavaFaker

// Maven / Gradle // implementation 'com.github.javafaker:javafaker:1.0.2' import com.github.javafaker.Faker; import java.util.Locale; Faker faker = new Faker(new Locale("pt-BR")); String nome = faker.name().fullName(); String cpf = faker.cpf().valid(); String email = faker.internet().emailAddress(); String telefone = faker.phoneNumber().cellPhone();

Go: gofakeit

// go get github.com/brianvoe/gofakeit/v6 import "github.com/brianvoe/gofakeit/v6" type Pessoa struct { Nome string Email string Telefone string } p := Pessoa{ Nome: gofakeit.Name(), Email: gofakeit.Email(), Telefone: gofakeit.Phone(), }

Factories: dados coerentes entre entidades

Em aplicações com relacionamentos (Cliente → Pedido → Item), factories garantem consistência:

Exemplo em JavaScript/TypeScript

import { faker } from "@faker-js/faker/locale/pt_BR"; // factory: cliente export function criarCliente() { return { id: faker.string.uuid(), nome: faker.person.fullName(), email: faker.internet.email(), cpf: faker.br.cpf(), criadoEm: faker.date.past(), }; } // factory: pedido (requer clientId) export function criarPedido(clienteId: string) { return { id: faker.string.uuid(), clienteId, valor: Number(faker.commerce.price({ min: 50, max: 5000 })), status: faker.helpers.arrayElement(["novo", "pago", "enviado", "entregue"]), criadoEm: faker.date.recent(), }; } // factory: cliente com N pedidos export function criarClienteComPedidos(numeroPedidos = 3) { const cliente = criarCliente(); const pedidos = Array.from({ length: numeroPedidos }, () => criarPedido(cliente.id), ); return { cliente, pedidos }; } // Uso const { cliente, pedidos } = criarClienteComPedidos(5);

FactoryBot em Ruby (padrão Rails)

# spec/factories/clientes.rb FactoryBot.define do factory :cliente do nome { Faker::Name.name } email { Faker::Internet.email } cpf { Faker::CPF.number } trait :com_pedidos do after(:create) do |cliente| create_list(:pedido, 3, cliente: cliente) end end end factory :pedido do association :cliente valor { Faker::Commerce.price(range: 50.0..5000.0) } status { Pedido.statuses.keys.sample } end end # Uso em teste cliente = create(:cliente, :com_pedidos) # Cria cliente + 3 pedidos associados

Seed determinístico para CI reprodutível

Testes que geram dados aleatórios são pesadelos para debugar. Solução: seed fixo.

JavaScript / TypeScript

import { faker } from "@faker-js/faker"; // Em setup de testes (vitest/jest) beforeAll(() => { faker.seed(42); }); // Cada chamada produz o mesmo valor entre execuções faker.person.firstName(); // sempre "João" (exemplo) faker.person.firstName(); // sempre "Maria"

Python

from faker import Faker fake = Faker("pt_BR") Faker.seed(42) # Agora gera sequência determinística fake.name() # sempre mesmo nome fake.name() # sempre mesmo próximo

Dica

Em CI, use seed do build number. PR #42 → seed 42. Benefícios: mesma PR reroda com mesmo dado (reprodutibilidade); PRs diferentes exercitam dados diferentes (cobertura). Combina reprodutibilidade com variação.

Seed de banco: estratégias

Para desenvolvimento local

// db/seed.ts import { db } from "./db"; import { criarCliente, criarPedido } from "./factories"; async function seed() { if (process.env.NODE_ENV === "production") { console.error("NUNCA rode seed em produção!"); process.exit(1); } console.log("Criando 100 clientes..."); for (let i = 0; i < 100; i++) { const cliente = await db.cliente.create({ data: { ...criarCliente(), isTest: true }, }); // 1-5 pedidos por cliente const numPedidos = Math.floor(Math.random() * 5) + 1; for (let j = 0; j < numPedidos; j++) { await db.pedido.create({ data: { ...criarPedido(cliente.id), isTest: true }, }); } } console.log("Seed completo!"); } seed();

Atenção

A flag isTest: true é crítica. Em produção, filtros por isTest: false evitam que teste misture com dados reais. Também facilita limpeza periódica de ambiente staging: DELETE WHERE is_test = true AND created_at < NOW() - INTERVAL ‘30 days’.

Para staging persistente

  • Marque todos os registros com is_test = true.
  • Limpe periodicamente (30-60 dias) para não acumular lixo.
  • Regenere antes de demos importantes para cenários frescos.
  • Documente o processo de seed no README.

Cenários específicos

Usuário com padrões de compra realistas

// Cliente fiel (muitos pedidos, valor médio) export function criarClienteFiel() { const cliente = criarCliente(); const pedidos = Array.from({ length: faker.number.int({ min: 20, max: 50 }) }, () => ({ ...criarPedido(cliente.id), valor: faker.number.float({ min: 100, max: 500 }), }), ); return { cliente, pedidos }; } // Cliente novo (poucos pedidos, valor baixo) export function criarClienteNovo() { const cliente = { ...criarCliente(), criadoEm: faker.date.recent({ days: 30 }) }; const pedidos = Array.from({ length: faker.number.int({ min: 1, max: 3 }) }, () => ({ ...criarPedido(cliente.id), valor: faker.number.float({ min: 50, max: 150 }), }), ); return { cliente, pedidos }; } // Cliente VIP (poucos pedidos, valor altíssimo) export function criarClienteVip() { const cliente = criarCliente(); const pedidos = Array.from({ length: faker.number.int({ min: 3, max: 10 }) }, () => ({ ...criarPedido(cliente.id), valor: faker.number.float({ min: 5000, max: 50000 }), }), ); return { cliente, pedidos }; }

Distribuição realista com weights

// Gera mix realista de clientes: 70% novos, 25% fiéis, 5% VIP export function gerarBaseClientes(total: number) { const clientes = []; for (let i = 0; i < total; i++) { const tipo = faker.helpers.weightedArrayElement([ { value: "novo", weight: 70 }, { value: "fiel", weight: 25 }, { value: "vip", weight: 5 }, ]); switch (tipo) { case "novo": clientes.push(criarClienteNovo()); break; case "fiel": clientes.push(criarClienteFiel()); break; case "vip": clientes.push(criarClienteVip()); break; } } return clientes; }

Documentos brasileiros específicos

Para CPFs, CNPJs, CEPs e dados locais, faker-js/locale/pt_BR cobre a maioria:

Métodos Faker-js para dados brasileiros
CritérioExemplo de saída
faker.br.cpf()14339725095
faker.br.cnpj()62030781000162
faker.person.fullName()João da Silva
faker.phone.number()(11) 98765-4321
faker.location.city()São Paulo
faker.location.state()São Paulo (ou SP)
faker.location.zipCode()01001-000
faker.company.name()Empresa XYZ LTDA

Anonimização de dados de produção

Em alguns cenários (performance testing com distribuição real), você precisa de dados que refletem produção. Anonimize antes de copiar para staging:

// Script de anonimização import { faker } from "@faker-js/faker/locale/pt_BR"; import crypto from "crypto"; function anonimizar(registro: Record<string, unknown>) { return { ...registro, // Mantenha ID (preserva relacionamentos) // id: registro.id, // Substitua PII nome: faker.person.fullName(), email: faker.internet.email(), cpf: faker.br.cpf(), telefone: faker.phone.number(), // Hash de campos sensíveis que precisam ser únicos senha: crypto.randomBytes(32).toString("hex"), // Mantenha valores numéricos e datas para análise // valor, created_at, etc. }; } // Rode uma vez ao migrar de prod para staging const dadosProducao = await buscarDadosDeProducao(); const anonimizados = dadosProducao.map(anonimizar); await salvarEmStaging(anonimizados);

Vai mais fundo

Anonimização verdadeira é difícil de fazer bem. Nomes únicos em cidade pequena + cargo específico podem reidentificar mesmo com CPF trocado. Para dados sensíveis ou altamente identificáveis, prefira dados 100% fictícios gerados com Faker.

Teste de carga com volume realista

Para testar performance com milhões de linhas, gere em batch e persista:

import { faker } from "@faker-js/faker/locale/pt_BR"; import { createWriteStream } from "node:fs"; import { stringify } from "csv-stringify"; const TOTAL = 1_000_000; const BATCH = 10_000; const stream = createWriteStream("./dados-teste.csv"); const csv = stringify({ header: true, columns: ["id", "nome", "cpf", "email"] }); csv.pipe(stream); for (let i = 0; i < TOTAL; i += BATCH) { const batch = Array.from({ length: BATCH }, () => ({ id: faker.string.uuid(), nome: faker.person.fullName(), cpf: faker.br.cpf(), email: faker.internet.email(), })); for (const row of batch) csv.write(row); console.log(`Progresso: ${i + BATCH} / ${TOTAL}`); } csv.end(); console.log("CSV com 1M registros gerado.");

Erros clássicos

  • Usar dados reais “só esta vez”: vira prática.
  • Seed na maioria dos testes, sem em alguns: inconsistência confusa.
  • Factories sem helpers de variação: sempre cria o mesmo cenário, não exercita edge cases.
  • Não marcar registros como teste: risco de misturar com produção.
  • Gerar cartão de crédito que passa Luhn mas é de testador real: violação se a pessoa reclamar.
  • Dados em inglês em sistema PT-BR: use locale correto.
  • Gerar em produção por engano: sempre verifique NODE_ENV antes.
  • Ignorar distribuição realista: todos os clientes com 10 pedidos não é cenário real.

Checklist de uso saudável

  • Biblioteca de faker correta para a linguagem instalada?
  • Locale correto configurado (pt_BR para apps brasileiros)?
  • Seed determinístico em CI?
  • Flag isTest: true em todos os registros de teste?
  • Seed script verifica ambiente antes de rodar?
  • Factories para entidades relacionadas?
  • Cenários com distribuição realista (não uniforme)?
  • Limpeza periódica de staging?
  • Documentação do processo de seed no README?

Dados fictícios em uma frase

Dados fictícios transformam testes de frágeis e ilegais em robustos e conformes com LGPD. Bibliotecas como Faker-js e Faker (Python) resolvem 95% dos casos em poucas linhas. Combinado com factories e seed determinístico, você tem arsenal completo para qualquer cenário — de unit test minúsculo a load test com milhões de registros.

Perguntas frequentes

Por que não usar dados reais em testes?+

Quatro razões. (1) LGPD: usar dado real em testes sem base legal viola a lei. (2) Vazamento: staging tem menos segurança que prod; dados reais ali viram risco de incidente. (3) Reprodutibilidade: cenários de teste precisam de dados controlados. (4) Volume: você não tem dados reais suficientes para teste de carga. Dado fictício resolve os 4 com zero risco jurídico.

Qual a diferença entre mock, fake e stub?+

Fake/dado fictício: objeto com dados realistas usado como entrada (Faker gera). Stub: retorno predeterminado de função mockada (ex: API responde sempre 200). Mock: objeto que verifica interações esperadas (métodos foram chamados, com quais argumentos). Os três se complementam em testes. Este artigo foca em fakes/dados fictícios — a base de qualquer bom teste.

Qual biblioteca de fake data é padrão em JavaScript?+

@faker-js/faker é o padrão absoluto em 2026. ~350k downloads/semana, mantido ativamente, suporta múltiplos idiomas (incluindo pt_BR), geração de nomes, CPFs, endereços, UUIDs, datas, e mais. Alternativas: chance.js (mais focado em valores aleatórios), casual (leve). Para dados brasileiros específicos: brazilian-values, @fake-br/faker. Para 90% dos casos, faker-js basta.

Seed determinístico é obrigatório em CI?+

Fortemente recomendado. Sem seed, cada execução gera dados diferentes — um teste que falha em CI pode ser impossível de reproduzir localmente. Com seed fixo (faker.seed(42)), mesma execução → mesmos dados → bug consistente. Em pipeline de CI: use seed baseado em número do build (PR #42 → seed 42), garantindo variação entre PRs mas reprodutibilidade dentro do mesmo PR.

Quando dados fictícios NÃO bastam?+

Testes que dependem de padrões específicos de produção: (1) performance em queries que sofrem com distribuição de dados (scan vs index); (2) edge cases descobertos em prod que não aparecem em dados aleatórios; (3) bugs que envolvem escala (milhões de linhas com padrões reais). Solução: use produção anonimizada — mascare CPF, nome, e-mail, mantendo distribuição estatística e relacionamentos.

Como gerar dados fictícios coerentes entre entidades?+

Use factories com relações. Ex: Pedido tem cliente_id; gere cliente primeiro, use id no pedido. Frameworks como factory_bot (Ruby) e FactoryBot (JS) resolvem. Em Faker puro, crie função factory_cliente() que retorna um cliente completo, depois factory_pedido(clientId) que usa o ID retornado. Dados relacionais coerentes facilitam debug — quando falha, o cenário faz sentido.

Faker gera dados que passam em validação (CPF, CNPJ, cartão)?+

Depende. Faker.br.cpf() gera CPF que passa no módulo 11 (válido matematicamente). Cartão de crédito: faker.finance.creditCardNumber() gera número válido pelo algoritmo de Luhn mas não é cartão real. Telefone, CEP, cor, UUID: todos válidos em formato. Para cenários específicos, verifique a doc. Em dúvida, rode validador sobre o gerado — se falha, implemente gerador custom.

Quanto tempo leva para gerar 1 milhão de registros fictícios?+

Em Node.js com Faker: ~30-60 segundos (dependendo da complexidade do objeto). Em Python com Faker: ~2-3 minutos. Para volumes maiores ou performance crítica, gere em batch e persista em CSV para reuso. Mimesis (Python) é 3-5x mais rápido que Faker. Para hiper-escala, considere gerar em SQL direto com random() nativo do Postgres.

#dados fictícios#fake data#faker#testes#lgpd#factory#seed#ci#mocking

Artigos relacionados