Datos

Generador de Factories para Testing

Armá factories de test robustas en segundos. Patrones probados para Jest, Mocha, PHPUnit y más frameworks, con datos consistentes que tus tests necesitan.

Instantáneo🔒En tu navegadorSin registro
En vivo
    Ver como texto

    Por qué usar factories en lugar de fixtures estáticos

    Los fixtures hardcoded generan acoplamiento brutal: cambias un campo de User y rompes 47 tests. Las factories generan datos bajo demanda con valores razonables por default y override quirúrgico donde importa. Un test de login solo necesita email/password válidos; el resto (createdAt, address, preferencias) puede ser ruido faker. Tres ventajas clave: 1) Tests aislados sin dependencias de orden, 2) Setup explícito de lo relevante (user.withRole('admin')), 3) Mantenimiento centralizado cuando el schema evoluciona.

    Factory Boy de Python y FactoryBot de Ruby popularizaron el patrón. En JS, libraries como Fishery (TypeScript-first) o Rosie te dan DSLs fluidos. El secret está en los traits: en vez de copypastear userFactory() 20 veces con tweaks, definís .pending(), .verified(), .suspended() y componés. PHPUnit no tiene factory nativa, pero DataProviders + builders custom funcionan igual.

    Errores comunes: llenar factories con lógica de negocio (eso va en la entidad), generar IDs que colisionan (usá sequences o UUIDs), y no limpiar side-effects (si la factory persiste, tu tearDown debe borrar).

    Anatomía de una factory bien diseñada

    Estructura típica: defaults sensatos (faker para nombres, enums válidos, foreign keys null-safe), traits componibles (withOrders, expired, premium), lazy evaluation (createdAt se resuelve al momento de build, no al definir la factory), y hooks (afterBuild para cálculos derivados, afterCreate para llamadas a API externas si es integration test).

    Ejemplo en TypeScript con Fishery:

    const userFactory = Factory.define<User>(({ sequence, afterBuild }) => ({
      id: sequence,
      email: faker.internet.email(),
      role: 'user',
      createdAt: new Date()
    })).trait('admin', { role: 'admin' });

    Ahora userFactory.admin().build() te da un admin, y .build({ email: 'test@foo.com' }) hace override quirúrgico. El sequence garantiza IDs únicos por test run.

    Para relaciones: lazy attributes. Si Order tiene customerId, la factory de Order puede recibir un customer opcional o generar uno default con customerFactory.build(). Así evitas explosion combinatoria de fixtures.

    Factories para APIs y mocks de red

    Testing de frontends o integraciones con APIs implica mockear responses HTTP. Factories aca brillan: definís responseFactory con status 200, headers default, body según schema OpenAPI/GraphQL. Traits para errores: .notFound(), .serverError(), .rateLimited().

    Libraries como MSW (Mock Service Workers) se integran perfecto: interceptas fetch(), devolvés responseFactory.success({ data: userFactory.buildList(5) }). Tus tests quedan semánticos: 'when API returns empty list' usa .build({ data: [] }); 'when user is banned' usa userFactory.banned().

    Caso real: GraphQL con nodos paginados. Tu factory genera edges con cursor, pageInfo con hasNextPage calculado, y nodes con el schema correcto. Snapshots de Jest validan la forma; factories te dan variedad (página vacía, un item, página llena, error parcial).

    Truco pro: exporta factories desde __tests__/factories para reuso cross-suite. Un userFactory usado en 30 archivos es mejor que 30 copias levemente distintas.

    Seeders deterministas y tests no-flaky

    Faker random causa flakiness: un test pasa con 'John Doe' pero falla con 'X Æ A-12' porque tu validador regex rompe. Solución: seed fijo por test. En beforeEach: faker.seed(12345). Ahora cada run genera la misma secuencia pseudoaleatoria. CI y local dan idénticos resultados.

    Alternativa: valores hardcoded para campos sensibles (email siempre 'test@example.com'), faker solo para relleno cosmético (bio, avatar URL). Algunos equipos usan snapshot factories: la primera corrida genera JSON fixtures, commits siguientes los reusan (package jest-serializer-factory).

    Para tests de integración que tocan DB real, las factories deben hacer cleanup. En Jest: afterEach(async () => { await cleanupUsers(createdIds); }). Track IDs generados en un Set, borrá todo al final. TestContainers + factories = paraíso: cada test tiene su Postgres efímero, factories populan, test corre, container muere.

    Edge cases: factories de dates. Si tu lógica depende de 'hace 3 días', usa subDays(new Date(), 3) en la factory, no un timestamp hardcoded que quedará obsoleto. Lo mismo timezone: factories deben generar UTC o el TZ de tu app, nunca mezclar.

    Preguntas frecuentes

    ¿Factories van en src/ o tests/?

    En tests/ o __tests__/factories/. Son código de testing, no de producción. Algunos proyectos los exportan en un package @myapp/test-utils si hay múltiples repos.

    ¿Puedo usar factories en integration tests con DB real?

    Sí, pero asegurate de hacer cleanup (afterEach) y usar transactions o contenedores efímeros para evitar side-effects entre tests.

    ¿Qué hago si mi entidad tiene 40 campos?

    Define defaults razonables para todos, expone solo los relevantes con traits. La mayoría de tests no necesita override de 40 campos, solo 2-3 clave.

    ¿Factories son solo para unit tests?

    No, son geniales para integration, E2E (seedear DB de staging), y hasta demos/storybook. Cualquier lugar que necesite datos consistentes.

    ¿Te sirvió este generador?