Surtout jusqu'à ce que vous puissiez créer et déployer l'application que vous développez et la voir à l'écran Cela prend 5 minutes et 10 minutes, mais dans ce cas, L'opération d'écrire la logique métier mais de la tester uniquement manuellement ne produit que de la douleur.
Dans cet article, Je sais qu'il vaut mieux l'écrire d'une manière ou d'une autre, mais honnêtement, je ne sais pas comment l'écrire avec la structure actuelle, Aux développeurs qui n'auraient pas envie de dépenser autant parce qu'ils ne savent pas de quoi ils sont heureux. Il fournit une méthode de conception pour écrire efficacement des tests unitaires avec xUnit.
En gros, il s'agit de java8 et JUnit4, mais le contenu n'est pas si limité en langage.
Les tests unitaires ne peuvent vérifier le comportement d'une fonction que par assertion.
Les tests manuels sont le moyen le plus efficace de détecter les défauts inconnus.
Plutôt que d'améliorer la qualité, il est possible d'effectuer automatiquement les vérifications minimales afin que la vitesse de développement soit ralentie en étant ennuyeuse et que des retouches inattendues ne se produisent pas plus tard.
Évidemment, cet article est destiné aux personnes qui n'écrivent généralement pas de tests unitaires, donc juste au cas où.
Comme dans l'exemple ci-dessus, il faut 5 minutes et 10 minutes pour pouvoir vérifier depuis l'écran, mais dans ce cas, Pour une logique métier complexe, il est plus efficace de générer une retouche avant de tester à partir de l'écran.
Les tests unitaires vous permettent généralement de voir les résultats plus rapidement que vous ne pouvez démarrer le serveur et le voir à l'écran. Aussi, comme le nom du test unitaire (unitaire), il est possible de vérifier au niveau de chaque fonction avant de connecter toutes les fonctions. Une autre raison est que le délai de mise en œuvre => de validation est plus petit.
En d'autres termes
Dans ces deux points, les retouches peuvent être détectées rapidement.
Souvent mentionné comme un mérite du TDD, Les tests unitaires sont généralement écrits sous la forme d'assertions (comme la valeur de retour de la fonction XX doit être ZZ lorsque l'argument est YY). Cela permet aux développeurs suivants de ** écrire avec succès ** en lisant le code de test pour le test unitaire. Vous saurez le plus clairement que "cette fonction a de telles spécifications".
(Bien écrire est très important, C'est assez déroutant s'il n'a pas à la fois l'exhaustivité en tant que scénario de test et la lisibilité en tant que code.)
Non seulement les développeurs peuvent le comprendre, bien sûr. Si un développeur qui ne comprend pas la fonction fait une mauvaise modification, Tant que le CI tourne correctement Il est possible de détecter automatiquement que "le comportement a changé par rapport aux spécifications souhaitées" dans le test unitaire.
Un bon entretien des tests unitaires est Cela conduit à la possibilité de détecter automatiquement des défauts qui, autrement, ne seraient remarqués qu'au stade du test d'intégration.
Ceci est également souvent cité comme un avantage du TDD, Le code de test sera le premier utilisateur de la fonction publique (prévue) que vous implémentez.
Surtout en Java, je pense personnellement que la conception de la signature détermine divers facteurs tels que l'évolutivité et le risque de modification. En appelant réellement la fonction à partir du code de test, il est souvent possible de retrouver l'utilisabilité de la fonction.
Si vous remarquez cela après avoir été appelé à partir de différentes classes, le risque et la portée de la modification seront énormes.
Lors d'un test combiné, il y a une interdiction. Le fait est que les valeurs qui ne peuvent pas être saisies à partir de l'écran sont exclues du scénario de test en tant que règle interdite. Dans ce cas, le jugement selon lequel "vous ne pouvez pas entrer depuis l'écran" n'est pas fiable.
Par exemple, même si le frontal est validé, Cela n'a aucun sens si la valeur est réécrite par un utilisateur malveillant au moment de l'envoi.
Étant donné que le test unitaire n'a pas la restriction qu'il peut être saisi ou ne peut pas être Même pour les modèles d'entrée qui sont des cas interdits Il est possible de tester.
Ce serait bien de pouvoir écrire un test qui s'attend à ce qu'une exception soit levée.
Eh bien, j'ai donné divers mérites, Si vous lisez cet article, comme mentionné précédemment, sans écrire de test unitaire, Je suis aux prises avec un travail de développement d'applications à grande échelle chaque jour.
Pourquoi je ne l'ai pas écrit, pourquoi mes aînés autour de moi Considérant que personne n'a écrit à perte de vue Peut-être en fait En premier lieu, cela peut être dû au fait que le code produit a une structure qui rend difficile l'écriture de tests unitaires.
Dans cette section, "Pourquoi ne puis-je pas écrire un test unitaire?" Je vais vous expliquer les fonctionnalités lorsque la structure est difficile à écrire un test unitaire.
Ici, comme une fonction commune sur votre lieu de travail Imaginez quelque chose nommé «complet» qui est responsable du processus d'achèvement de quelque chose.
public Map<String,Object> complete(BigBean bigBean) {
// ...
SomeKindOfConfig config = dao.loadConfig(someId);
this.computeSomeValue(bigBean);
if(config.getSomeAttribute() == 1) {
// ...
} else {
// ...
}
// ...
for(DtlBean dtl : bigBean.getManyDtls()) {
// ...
}
if(bigBean.getOtherAttribute() == 0) {
// ...
}
dao.updateSomething(bigBean);
return res;
}
Lors de l'exécution de quelque chose Je pense qu'il est courant de créer un design fonctionnel qui est pratique car divers processus peuvent être effectués en appuyant simplement sur un bouton. C'est un modèle dans lequel ils sont tous écrits dans une fonction.
Un tel traitement est souvent effectué Je dois essayer ce paramètre plus tard et brancher le processus! Parce que cela peut être une situation difficile comme L'accès à la base de données est également chaotique, comme entrer ad hoc sur le chemin.
Pour une logique métier qui ressemble à cet héritage Les tests unitaires sont très difficiles à écrire.
Il y a divers problèmes autres que le fait d'être trop long, Si vous le faites souvent avec une fonction, Il est difficile d'écrire sous la forme d'une assertion que "la sortie devrait être comme ça pour l'entrée" C'est une caractéristique importante. Comme il y a de nombreuses branches et que la combinaison explose, la quantité de description de classe de test devient énorme, ce qui est inefficace.
private void computeSomeValue(BigBean bigBean) {
//...
bigBean.setSomeValue(someValue);
//...
}
S'il existe une méthode void dont le contenu de l'argument peut changer D'autre part Puisqu'il devient impossible d'écrire clairement l'affirmation que "quand il y a une telle entrée, cela devrait être comme ça comme une sortie" Je pense que vous devriez l'éviter autant que possible.
Si vous souhaitez vraiment répondre aux exigences ci-dessus, La signature elle-même,
private SomeValueClass computeSomeValue(BigBean bigBean) {
//...
return someValue;
}
Il vaut mieux écrire comme ça.
Selon le fonctionnement du test unitaire, Si quelque chose comme un environnement de test n'est pas prêt pour une actualisation rapide Par exemple, il n'est pas facile de tester un DB dépendant de la valeur avec un test unitaire.
Dans le cas du processus ci-dessus Je vais obtenir une valeur semblable à un paramètre de la base de données en cours de route, Cela entraînera une assertion de méthode complète pour le même argument Selon l'état de la base de données, il réussira ou échouera.
En premier lieu, pour les développeurs ultérieurs Je pense que c'est une mauvaise implémentation d'aller du coup voir les réglages en cours de route.
Dans ce cas, simulez Dao avec Mockito côté test unitaire, etc. Il existe un moyen de gérer cela.
Une fonction de complexité qui n'explose pas la combinaison de branches, S'il est mis en œuvre séparément dans un état faiblement couplé, Vous pouvez implémenter et exécuter des tests unitaires très efficacement.
Par exemple, disons que vous avez la possibilité de payer un loyer pendant plusieurs mois par jour. Nous mettrons en place une fonction de prévisualisation qui vous permettra de voir combien de loyer vous paierez dans le mois.
Comme argument
Il y aura.
En sortie,
--La date est affichée en AAAA / MM / JJ.
Supposons que ce soit une spécification.
Si vous essayez de tout connecter à partir de l'écran et de le frapper normalement,
--Quand il y en a plusieurs? Quand c'est singulier? --Quand c'est un mois à deux chiffres? Quand c'est un mois à un chiffre? ――Quand avant? La prochaine fois?
Il y a diverses choses et cela a tendance à augmenter en combinaison.
Cependant, comme il s'agit d'un ensemble de spécifications simples si elles sont divisées, Si vous écrivez un test unitaire sur "une fonction qui ne formate qu'un seul mois" Vous pouvez voir que vous pouvez faire confiance au format de la lune dans une certaine mesure, Si vous écrivez une unité de "fonction pour trier plusieurs mois", Il n'est pas nécessaire de tester sans relâche l'ordre des «fonctions qui sortent en reliant le début à la fin de plusieurs mois avec des tirets». Et, "Comparez la date, l'année et le mois, et si l'année et le mois sont antérieurs," avant ", S'il y a un test unitaire de "une fonction qui renvoie" suivant "si l'année et le mois sont postérieurs", Le test unitaire de la fonction d'affichage de l'aperçu final est Il vous suffit de tester la valeur représentative pour savoir s'ils sont correctement combinés.
Si vous implémentez chacun comme un ensemble avec un test unitaire qui est petit et garantit une valeur de retour pour l'argument, "Au moins ça marche correctement jusqu'à présent, n'est-ce pas?" Il y a aussi l'avantage de pouvoir développer l'esprit tranquille car on peut procéder en vérifiant.
An expression is said to be referentially transparent if it can be replaced with its corresponding value without changing the program's behavior. As a result, evaluating a referentially transparent function gives the same value for same arguments.
https://en.wikipedia.org/wiki/Referential_transparency
"Une fonction est la référence transparente signifie que le comportement du programme ne change pas même si la fonction est remplacée par sa valeur de retour. Par conséquent, lorsque vous exécutez une fonction transparente à la référence, ** renvoie toujours la même valeur de retour pour le même argument **. "
Écrivez la logique métier qui vous tient à cœur dans une référence transparente. Personnellement, je suis heureux de séparer clairement la classe qui a l'état de la fonction qui renvoie la sortie pour l'entrée.
Non seulement il est facile d'écrire un test unitaire, mais il est également facile d'écrire si la même valeur de retour est toujours renvoyée pour le même argument. Il rend le test unitaire efficace en ce qu'il "reproduit le mouvement garanti par le test unitaire dans n'importe quel état".
Je pense qu'il y a des règles ici.
Lors de la rédaction d'un test unitaire comme description de spécifications, Cependant, il peut être contre-productif de transmettre la valeur qui est arrivée au nuage noir et de faire une affirmation.
Tout d'abord, le minimum
Il est efficace de saisir certaines des méthodes généralement connues sous le nom de méthodes de test.
Au contraire, dans le cas d'une fonction qui ne peut pas être mise dans le cas avec ces deux Puisque le test lui-même dans le test unitaire peut ne pas convenir, Vous voudrez peut-être envisager la validation avec d'autres méthodes.
@Runwith(Theories.class)
Ou
@Runwith(Parameterized.class)
Vous pouvez utiliser pour tester en passant plusieurs "ensembles d'arguments et de valeurs attendues" à un code de test. En bref, vous pouvez rendre les entrées et les sorties complètes et faciles à écrire.
Si le nombre de classes de test augmente Créez une classe Suite qui la regroupe pour chaque package, Soyons capables de tourner toutes les classes de test sous lui à la fois à tout moment.
S'il y a un changement Si vous retournez tout immédiatement, Tant qu'il est affirmé dans le test unitaire, il fonctionnera avec les spécifications jusqu'à présent, Vous pouvez voir immédiatement.
Pour les projets qui utilisent des outils CI tels que Jenkins et travis Je pense que c'est une bonne idée de revenir en arrière lorsque des modifications sont apportées à la base de code.
C'était tout.
Recommended Posts