Dans la vie de chaque développeur, il arrive un moment où il pense à créer un composant de test pour son idée originale. Je vais mieux - dans la vie de tout bon développeur. Lorsque vous êtes junior et ne portez aucune responsabilité particulière, vous avez droit à de nombreuses erreurs et vous pouvez les corriger à tout moment. Vous n'êtes pas responsable du produit que vous créez et n'avez pas la motivation de passer une minute supplémentaire pour revérifier le code généré. «Rien, ce montant ne peut pas être reproduit», «cette chose semble fonctionner», «enfin, au moins, il fait ce qu'il faut» - si vous voulez dépasser le niveau de la pépinière de programmeur, vous devrez nier chacune de ces pensées.
Avec le développement de votre propre expérience de programmation, vous avez de nouveaux clients de plus en plus cool / gros. Vous serez même ravi de certains (de tous, si vous avez de la chance) - les gens sont bons, ils paient généreusement et ne sont pas pointilleux sur les problèmes qui se posent. Regardons un cas aussi simple (très simple, mais l'essentiel qui se cache derrière) de créer un gestionnaire de formulaire à partir d'un programmeur qui ne connaît pas les tracas.
Ainsi, la tâche simple est arrivée - écrire un gestionnaire de formulaire. L'objectif est d'accepter les demandes des clients pour l'achat de briques. Le client est grand, il est engagé dans de grandes livraisons de briques en vrac (par exemple, pour un montant de plus de 500 000 roubles - afin de se sentir au moins un certain niveau de responsabilité pour ce qui se passe). La concurrence est féroce - les clients peuvent se rendre rapidement chez le fournisseur de briques s'ils ne répondent pas dans la journée.
Notre programmeur a été informé qu'il était nécessaire de sauvegarder les données du client à partir du formulaire - le nom du représentant, le numéro de téléphone, le nom de l'entreprise du client, le volume de la commande et un champ de description de commande facultatif. Cerveau de Porakinine, un formulaire simple a été rapidement créé avec des champs standards pour l'avant du site:

Les données du formulaire sont envoyées par une demande AJAX, sans recharger la page. De plus, le programmeur prend en charge la conception du gestionnaire de formulaires et il doit faire face à une tâche plutôt triviale - ajouter des enregistrements pour le nouveau client à la table des commandes existante et envoyer au client un e-mail avec une notification sur le nouveau client.

Le formulaire fonctionne, les données sont enregistrées avec succès, le client est satisfait. Mais tout d'un coup, un appel en colère vient du client, "alors ils disent que la commande est arrivée - la société millionnaire veut m'acheter toutes les briques, mais le numéro de téléphone n'est pas venu du formulaire et comment puis-je les contacter maintenant?! Demain, ils trouveront un autre fournisseur! Comment tu as fait quoi?! C'est ta faute ... " Le client se déchire et se balance, moins les nerfs, moins la confiance et moins le respect. La situation est extrêmement standard pour un junior - l'absence de toute validation et test des données entrantes du formulaire. La première tâche (validation) est résolue extrêmement simplement en ajoutant des règles de validation:

Désormais, le client du site n'indiquera que les données correctes dont nous avons besoin pour un traitement ultérieur. Au même stade, le développeur a l'idée de tester le code pour éviter davantage une situation aussi délicate. Par exemple, tester le champ du nom de famille ressemblera à ceci (pour simplifier l'exemple de base, la protection csrf est désactivée):

Nous savons qu'en l'absence de ce champ, le code devrait renvoyer une réponse avec une erreur et un état de 400 enregistré par nous. De telles méthodes de test sont prescrites pour chaque situation spécifique (ou validation de champ spécifique, tout dépend des tâches et de l'imagination du développeur).
Mais existe-t-il une méthode de développement différente de "Je l'ai fait, mais maintenant je vais vérifier"? Nous écrivons d'abord le code, tombons sur les montants d'exécution, le réparons, puis nous nous souvenons des tests. Cette approche peut aller de travers pour nous et nos clients, étant donné le client de plusieurs millions perdu (bien qu'en théorie, tous ces clients le seraient). Et puis je me suis demandé - que se passe-t-il si nous commençons la logique de création de l'application à partir de l'extrémité opposée - d'abord nous ferons des demandes à «l'exécuteur», puis nous le ferons répondre à ces exigences? Essayons.
On laisse la tâche comme avant, on ne change que l'approche. Nous devons écrire un gestionnaire de formulaire avec les champs fio, phone, corp, quant et content. Le résultat d'une exécution réussie est le statut 200, en ajoutant un champ à la commande avec le message «ok» et en renvoyant des données sur l'enregistrement saisi, d'autres options - le statut 400 et une liste d'erreurs.
Tout d'abord, nous devons écrire une méthode de test pour remplir valablement les données du formulaire:

Ensuite, créez la route et la méthode de contrôleur nécessaires (lorsqu'elles sont vides). Si nous exécutons le test maintenant, il devrait obtenir une erreur. La validation de données valides n'est pas tout ce dont nous avons besoin. Nous commençons maintenant à tester la validation des champs de formulaire. Nous déterminons quels champs sont requis - fio, phone, corp, quant et ajoutons une méthode de vérification (le commentaire est facultatif):

Le gestionnaire de formulaire devra simplement vérifier les données entrantes fio, phone, corp, quant. Puisque nous avons supprimé tous les champs obligatoires de la demande, une erreur dans les erreurs doit être renvoyée pour chacun d'eux. Dans le cas où au moins l'un d'entre eux n'est pas présent - le problème d'exécution. Si vous le souhaitez, vous pouvez ajouter un message de vérification, comme cela a été fait précédemment (vérifier «ok»).
Nous émettons une vérification de la longueur minimale des champs fio, phone et corp (une vérification similaire sera effectuée pour la longueur maximale et pour les caractères invalides dans ces champs).

Nos contrôles sont en place, vous pouvez exécuter et vérifier

Parfait. Notre application s'est écrasée dans 5 tests sur 5. Notre objectif supplémentaire est de passer par des méthodes de test qui définissent des valeurs non valides dans les champs et formulent des règles de validation pour les données entrantes. La logique est quelque chose comme ceci: le champ fio ne peut pas être vide; longueur d'au moins 3 et d'au plus 120; il s'agit d'une chaîne avec l'ensemble de caractères autorisé dans le nom (lettres, tirets, retraits). Le résultat de cette logique dans tous les domaines:

En réponse à un fichier, une liste d'erreurs a été ajoutée qui correspond à chaque champ «problème». Cela nous aidera à vérifier des champs spécifiques pour la validation (assertJsonStructure dans le fichier de test). Ensuite, nous ajoutons la méthode de validation et obtenons la version finale:

Et enfin, nous pouvons vérifier comment notre script fonctionne sur les tests (je me souviens, il y a eu 5 échecs en 5 tests).

Comme vous pouvez le voir, tous les tests ont réussi et une seule entrée a été entrée dans la base de données (car une seule méthode a été configurée pour fonctionner correctement).

Quelles sont les conclusions? Le développement d'applications, à commencer par les tests, est une meilleure option que l'écriture habituelle des fonctionnalités. La nécessité de ne recevoir de la méthode que ce qui est nécessaire est comparable à la discipline militaire - le code fait exactement ce que vous en avez besoin, pas un pas de côté. Cependant, cette approche a un côté négatif (bien que controversé) - le fait est que l'écriture de fonctionnalités supplémentaires (qui est en cours de test) prend également une partie du temps alloué pour le développement du projet. Quant à moi, le choix est clair - un bon programmeur devrait écrire des tests, et commencer par la fonctionnalité de test aide à écrire un projet fiable et qui fonctionne bien. Je vais essayer de l'utiliser dans quelque chose de moins trivial.