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.
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 !
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.
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 generateMockDataFromSchema accepte deux paramètres :
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, }); }
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.
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.
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; }
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; }
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, }); };
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; }
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; }
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, }); }
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 %.
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.
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!