Comment écrire assert correctement

Parlons maintenant des assertions.

Les affirmations sont l'une des choses considérées comme acquises, donc tout ici semble être des spécialistes. Quelqu'un utilise Java ou Junit intégré, quelqu'un utilise des bibliothèques avancées, quelqu'un construit les siennes.

Mais essayons d'aborder cela plus sérieusement. Comment, en fait, non?

Tout d'abord, les assertions font double emploi avec la spécification. Si la spécification shouldReturnValidOrder est spécifiée, cela doit être vérifié et non assertNotNull.

Deuxièmement, les assertions devraient être faciles à lire. C'est-à-dire, instantanément, en comparant avec la spécification.

S'il y a trop d'affirmations (à mon goût extrême, il y en a beaucoup plus, mais nous mettons une limite d'au moins cinq à sept), alors le test cesse d'être compréhensible. Pour de bon, chaque test ne devrait avoir qu'une seule raison de tomber.

Les actifs peuvent être dirigés vers: un champ primitif, un objet, une collection, rarement une fonction ou un thunk.

Plus l'objet est complexe, plus les assertions seront complexes et diverses, et plus il sera difficile de lire et de trouver des erreurs.

Les déclarations positives se lisent mieux que les déclarations doubles négatives.

Les méthodes standard sont mieux lues que les assistants personnalisés. (Qui sait qui et où a testé la bibliothèque des aides). Et les assertions devraient être dans le corps de la méthode de test, et non quelque part à l'arrière des assistants de test (le sonar jure à juste titre sur l'absence d'assertions).
Les actifs sur les champs sont plus compréhensibles que les assertions sur les objets, et en particulier sur les collections.

Dans le cas de champs imbriqués, il est logique de tester complètement.

Pas

assertNotNull(order.getCustomer().getName) 

mais

 assertNotNull(order) assertNotNull(order.getCustomer()) assertNotNull(order.getCustomer().getName()) 

Les assers ne vérifient pas simplement bêtement ce qui est retourné par la méthode, mais l'influencent. Et si nous pouvons le changer, alors nous devons le changer.

Il est relativement difficile de faire des affirmations sur les collections. Contiennent-ils des zéros, sont-ils triés, exactement comment sont-ils triés, comment les éléments sont-ils vérifiés pour l'égalité, etc. - tout cela fait des collections des objets difficiles à affirmer, surtout quand il y a une logique dans la méthode liée aux éléments des collections.

Par conséquent, une méthode comme:

 List<Order> getOrderList(List<OrderDao> orderDaoList){ return orderDaoList.stream().map(orderDao=>order.name(orderDao.getName).build()).collect(Collectors.toList()) } 

il est facile de le diviser en deux, un transformateur orderDao => commandez et testez-le séparément, et le second testera le mappage des collections sur le mappeur abstrait, et nous pouvons le tester sur le talon.

 List<Order> getOrderList(List<OrderDao> orderDaoList, OrderDaoToOrderMapper mapper){ return orderDaoList.stream().map(mapper::map).collect(Collectors.toList()) } 

D'un autre côté, les collections se prêtent bien à la typification et à l'expansion, c'est-à-dire nous pouvons relativement facilement créer une collection de son propre type avec toutes les propriétés testées, la co- et la contravariance, etc. Par conséquent, au lieu d'une liste générique, nous pourrions créer notre propre OrderList, ou OrderSet, ou OrderSortedSet, et plus spécifique, mieux c'est. Et les tests deviendront plus faciles.

Il n'est pas beaucoup plus difficile de faire des déclarations sur les fonctions que sur les objets, et elles sont bien typées dans certains langages, vous pouvez donc probablement recommander une meilleure frappe, c'est-à-dire au lieu de Func <Order, Order>, renvoyez certains OrderComparator.

Source: https://habr.com/ru/post/fr475276/


All Articles