Maison  >  Article  >  interface Web  >  Création d'un assistant TypeScript pour la génération de données simulées avec Zod et Faker

Création d'un assistant TypeScript pour la génération de données simulées avec Zod et Faker

Patricia Arquette
Patricia Arquetteoriginal
2024-11-07 18:52:02818parcourir

Building a TypeScript Helper for Mock Data Generation with Zod and Faker

Lors de la création d'applications, les données fictives peuvent s'avérer inestimables pour les tests, le développement et le prototypage. Grâce à la robuste validation de schéma de Zod et aux capacités de génération de données de Faker, nous pouvons créer un assistant puissant pour générer des données fictives réalistes et conformes au schéma pour n'importe quel schéma Zod.

Introduction

Dans ce guide, nous allons créer une fonction d'assistance generateMockDataFromSchema qui accepte un schéma Zod et renvoie des données fictives qui correspondent à la structure et aux règles de validation du schéma. Allons-y étape par étape !

Procédure pas à pas de l'article

  • Présentation
  • Solution pas à pas de l'article
  • Extraits de code
  • Pourquoi utiliser Zod et Faker pour des données simulées ?
  • Création du générateur de données fictives
    • La fonction d'assistance generateMockDataFromSchema
    • Gestion de chaque type de schéma
      • Chaînes avec exigences spécifiques
      • Valeurs numériques
      • Booléens
      • Tableaux
      • Champs facultatifs et nullables
      • Objets avec champs imbriqués
    • Exemple d'utilisation
    • Ajout d'options de personnalisation
    • Test de la fonction d'assistance
  • Conclusion

Extraits de code

  • Fonction d'assistance du générateur de données simulées
  • Exemple de réaction Stackblitz

Pourquoi utiliser Zod et Faker pour des données simulées ?

Avant de commencer à coder, voyons pourquoi Zod et Faker sont parfaits pour cette tâche :

  • Zod : fournit un moyen robuste et sûr de définir des schémas de données dans TypeScript. Ses capacités de validation de schéma garantissent que nos données fictives sont conformes à des règles spécifiques telles que les formats d'e-mail, les UUID ou les valeurs minimales/maximales.

  • Faker : génère des données aléatoires réalistes telles que des noms, des dates, des e-mails et des URL. Ceci est particulièrement utile lorsque nous avons besoin de données fictives qui ressemblent à des scénarios du monde réel, ce qui les rend parfaites à des fins de tests et de démonstration.

La combinaison de Zod et Faker nous donne la possibilité de créer des données fictives à la fois réalistes et conformes au schéma.

Création du générateur de données fictives

Le cœur de notre solution est la fonction d'assistance generateMockDataFromSchema, qui peut interpréter un schéma Zod et générer des données fictives correspondantes. Cette fonction gère différents types de données (chaîne, nombre, tableau, objet) et respecte les contraintes de validation au sein de chaque type de schéma. Explorons comment il est construit.

 La fonction d'assistance generateMockDataFromSchema

La fonction generateMockDataFromSchema accepte deux paramètres :

  • schéma : un schéma Zod qui définit la forme et les règles des données.
  • options (facultatif) : un objet pour personnaliser la longueur des tableaux et le comportement des champs facultatifs.

Voici la fonction, décomposée en chaque section pour expliquer la gestion des différents types de schémas.

import {
  ZodSchema,
  ZodObject,
  ZodString,
  ZodNumber,
  ZodBoolean,
  ZodArray,
  ZodOptional,
  ZodNullable,
  ZodTypeAny,
  ZodStringCheck,
} from "zod";
import { faker } from "@faker-js/faker";
import { z } from "zod";

const handleStringCheck = (check: ZodStringCheck) => {
  switch (check.kind) {
    case "date":
      return faker.date.recent().toISOString();
    case "url":
      return faker.internet.url();
    case "email":
      return faker.internet.email();
    case "uuid":
    case "cuid":
    case "nanoid":
    case "cuid2":
    case "ulid":
      return crypto.randomUUID();
    case "emoji":
      return faker.internet.emoji();
    default:
      return faker.lorem.word();
  }
};

type GeneratorPrimitiveOptions = {
  array?: {
    min?: number;
    max?: number;
  };
  optional?: {
    probability?: number;
  };
};

const getArrayLength = (options?: GeneratorPrimitiveOptions) => {
  return faker.number.int({
    min: options?.array?.min || 1,
    max: options?.array?.max || 10,
  });
};

export function generateTestDataFromSchema<T>(
  schema: ZodSchema<T>,
  options?: GeneratorPrimitiveOptions
): T {
  if (schema instanceof ZodString) {
    const check = schema._def.checks.find((check) => handleStringCheck(check));
    if (check) {
      return handleStringCheck(check) as T;
    }
    return faker.lorem.word() as T;
  }

  if (schema instanceof ZodNumber) {
    return faker.number.int() as T;
  }

  if (schema instanceof ZodBoolean) {
    return faker.datatype.boolean() as T;
  }

  if (schema instanceof ZodArray) {
    const arraySchema = schema.element;
    const length = getArrayLength(options);
    return Array.from({ length }).map(() =>
      generateTestDataFromSchema(arraySchema)
    ) as T;
  }

  if (schema instanceof ZodOptional || schema instanceof ZodNullable) {
    const probability = options?.optional?.probability || 0.5;
    return (
      Math.random() > probability
        ? generateTestDataFromSchema(schema.unwrap())
        : null
    ) as T;
  }

  if (schema instanceof ZodObject) {
    const shape = schema.shape;
    const result: any = {};
    for (const key in shape) {
      result[key] = generateTestDataFromSchema(shape[key] as ZodTypeAny);
    }
    return result as T;
  }

  throw new Error("Unsupported schema type", {
    cause: schema,
  });
}

Gestion de chaque type de schéma

Dans generateMockDataFromSchema, chaque type de schéma Zod (comme ZodString, ZodNumber, etc.) est géré différemment pour tenir compte de ses exigences uniques. Passons en revue chaque type.

Chaînes avec exigences spécifiques

Pour ZodString, nous devons prendre en compte toutes les vérifications spécifiques telles que l'e-mail, l'URL ou l'uuid. C'est là qu'intervient notre fonction d'assistance handleStringCheck. Elle inspecte le schéma de chaîne et, si des vérifications sont présentes, renvoie une valeur fictive pertinente (par exemple, un e-mail pour un e-mail, une URL pour une URL). Si aucune vérification spécifique n'est trouvée, il génère par défaut un mot aléatoire.

const handleStringCheck = (check: ZodStringCheck) => {
  switch (check.kind) {
    case "date":
      return faker.date.recent().toISOString();
    case "url":
      return faker.internet.url();
    case "email":
      return faker.internet.email();
    case "uuid":
    case "cuid":
    case "nanoid":
    case "cuid2":
    case "ulid":
      return crypto.randomUUID();
    case "emoji":
      return faker.internet.emoji();
    default:
      return faker.lorem.word();
  }
};

Dans generateMockDataFromSchema, nous utilisons cet assistant pour générer des données pour les champs de chaîne avec des vérifications.

Valeurs numériques

Pour ZodNumber, nous générons des entiers avec la méthode faker.number.int() de Faker. Cette partie peut être davantage personnalisée pour gérer les valeurs minimales et maximales si elles sont définies dans le schéma.

if (schema instanceof ZodNumber) {
  return faker.number.int() as T;
}

Booléens

Pour les booléens, Faker propose une simple fonction faker.datatype.boolean() pour générer aléatoirement des valeurs vraies ou fausses.

if (schema instanceof ZodBoolean) {
  return faker.datatype.boolean() as T;
}

Tableaux

Lorsque nous traitons avec ZodArray, nous générons récursivement des données fictives pour chaque élément du tableau. Nous permettons également de personnaliser la longueur du tableau à l'aide du paramètre options.

Pour générer des tableaux, nous décidons d'abord de la longueur à l'aide de getArrayLength, une fonction d'assistance qui vérifie les longueurs minimale et maximale dans les options. Pour chaque élément du tableau, generateMockDataFromSchema est appelé de manière récursive, garantissant que les schémas imbriqués dans les tableaux sont également gérés.

type GeneratorPrimitiveOptions = {
  array?: {
    min?: number;
    max?: number;
  };
  optional?: {
    probability?: number;
  };
};

if (schema instanceof ZodOptional || schema instanceof ZodNullable) {
  const probability = options?.optional?.probability || 0.5;
  return (
    Math.random() > probability
      ? generateTestDataFromSchema(schema.unwrap())
      : null
  ) as T;
}

const getArrayLength = (options?: GeneratorPrimitiveOptions) => {
  return faker.number.int({
    min: options?.array?.min || 1,
    max: options?.array?.max || 10,
  });
};

Champs facultatifs et nullables

Les champs facultatifs et nullables sont gérés en décidant de manière aléatoire s'il faut les inclure dans la sortie. Le paramètre options.optional.probability nous permet de contrôler cette probabilité. Si un champ est généré, il appelle generateMockDataFromSchema de manière récursive pour le schéma interne.

if (schema instanceof ZodOptional || schema instanceof ZodNullable) {
  const shouldGenerate =
    Math.random() > (options?.optional?.probability || 0.5);
  return shouldGenerate
    ? generateMockDataFromSchema(schema.unwrap(), options)
    : null;
}

Objets avec des champs imbriqués

Pour ZodObject, nous parcourons chaque paire clé-valeur et générons de manière récursive des données pour chaque champ. Cette approche prend en charge les objets profondément imbriqués, ce qui la rend très flexible.

if (schema instanceof ZodObject) {
  const shape = schema.shape;
  const result: any = {};
  for (const key in shape) {
    result[key] = generateMockDataFromSchema(shape[key] as ZodTypeAny, options);
  }
  return result as T;
}

Exemple d'utilisation

Avec generateMockDataFromSchema en place, voyons-le en action. Voici un exemple de schéma, UserSchema, avec différents types, champs facultatifs et tableaux imbriqués.

import {
  ZodSchema,
  ZodObject,
  ZodString,
  ZodNumber,
  ZodBoolean,
  ZodArray,
  ZodOptional,
  ZodNullable,
  ZodTypeAny,
  ZodStringCheck,
} from "zod";
import { faker } from "@faker-js/faker";
import { z } from "zod";

const handleStringCheck = (check: ZodStringCheck) => {
  switch (check.kind) {
    case "date":
      return faker.date.recent().toISOString();
    case "url":
      return faker.internet.url();
    case "email":
      return faker.internet.email();
    case "uuid":
    case "cuid":
    case "nanoid":
    case "cuid2":
    case "ulid":
      return crypto.randomUUID();
    case "emoji":
      return faker.internet.emoji();
    default:
      return faker.lorem.word();
  }
};

type GeneratorPrimitiveOptions = {
  array?: {
    min?: number;
    max?: number;
  };
  optional?: {
    probability?: number;
  };
};

const getArrayLength = (options?: GeneratorPrimitiveOptions) => {
  return faker.number.int({
    min: options?.array?.min || 1,
    max: options?.array?.max || 10,
  });
};

export function generateTestDataFromSchema<T>(
  schema: ZodSchema<T>,
  options?: GeneratorPrimitiveOptions
): T {
  if (schema instanceof ZodString) {
    const check = schema._def.checks.find((check) => handleStringCheck(check));
    if (check) {
      return handleStringCheck(check) as T;
    }
    return faker.lorem.word() as T;
  }

  if (schema instanceof ZodNumber) {
    return faker.number.int() as T;
  }

  if (schema instanceof ZodBoolean) {
    return faker.datatype.boolean() as T;
  }

  if (schema instanceof ZodArray) {
    const arraySchema = schema.element;
    const length = getArrayLength(options);
    return Array.from({ length }).map(() =>
      generateTestDataFromSchema(arraySchema)
    ) as T;
  }

  if (schema instanceof ZodOptional || schema instanceof ZodNullable) {
    const probability = options?.optional?.probability || 0.5;
    return (
      Math.random() > probability
        ? generateTestDataFromSchema(schema.unwrap())
        : null
    ) as T;
  }

  if (schema instanceof ZodObject) {
    const shape = schema.shape;
    const result: any = {};
    for (const key in shape) {
      result[key] = generateTestDataFromSchema(shape[key] as ZodTypeAny);
    }
    return result as T;
  }

  throw new Error("Unsupported schema type", {
    cause: schema,
  });
}

Ajout d'options de personnalisation

La fonction generateMockDataFromSchema accepte également un paramètre d'options facultatif pour personnaliser la longueur des tableaux et le comportement des champs facultatifs. Voici un exemple de la façon dont vous pouvez utiliser ces options :

const handleStringCheck = (check: ZodStringCheck) => {
  switch (check.kind) {
    case "date":
      return faker.date.recent().toISOString();
    case "url":
      return faker.internet.url();
    case "email":
      return faker.internet.email();
    case "uuid":
    case "cuid":
    case "nanoid":
    case "cuid2":
    case "ulid":
      return crypto.randomUUID();
    case "emoji":
      return faker.internet.emoji();
    default:
      return faker.lorem.word();
  }
};

Cela garantira que les champs du tableau ont une longueur comprise entre 2 et 5 et que les champs facultatifs sont générés avec une probabilité de 70 %.

Test de la fonction d'assistance

Pour confirmer que generateMockDataFromSchema fonctionne comme prévu, créez des tests unitaires pour différentes configurations de schéma. Voici un exemple de test pour un schéma de tableau :

if (schema instanceof ZodNumber) {
  return faker.number.int() as T;
}

En écrivant des tests pour différents types et configurations de schéma, vous pouvez vous assurer que la fonction d'assistance se comporte correctement dans différents scénarios.

Conclusion

En combinant Zod et Faker, nous avons créé un générateur de données fictives puissant et réutilisable, adapté aux projets TypeScript. La possibilité de tester différents scénarios et de voir des données réalistes en action le rend inestimable pour un développement rapide et des tests de qualité.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn