J'ai besoin de jouer un peu l'avocat des démons sur cette question car je ne peux pas bien la défendre par manque d'expérience. Voici l'affaire, j'obtiens conceptuellement les différences entre les tests unitaires et les tests d'intégration. En se concentrant spécifiquement sur les méthodes de persistance et le référentiel, un test unitaire utiliserait une maquette éventuellement via un framework comme Moq pour affirmer qu'un ordre recherché a été renvoyé comme prévu.
Disons que j'ai construit le test unitaire suivant:
[TestMethod]
public void GetOrderByIDTest()
{
//Uses Moq for dependency for getting order to make sure
//ID I set up in 'Arrange' is same one returned to test in 'Assertion'
}
Donc, si je mets en place OrderIdExpected = 5
et mon objet maquette revient 5
comme l'ID mon test passera. J'ai compris. J'ai testé le code à l' unité pour m'assurer que ce que mon code préforme renvoie l'objet et l'ID attendus et pas autre chose.
L'argument que j'obtiendrai est le suivant:
"Pourquoi ne pas simplement sauter les tests unitaires et faire des tests d'intégration? C'est tester la procédure stockée de la base de données et votre code ensemble qui est important. Cela semble trop de travail supplémentaire d'avoir des tests unitaires et des tests d'intégration quand finalement je veux savoir si la base de données appelle et le code fonctionne. Je sais que les tests prennent plus de temps, mais ils doivent être exécutés et testés malgré tout, il me semble donc inutile d'avoir les deux. Il suffit de tester ce qui compte. "
Je pourrais le défendre avec une définition de manuel comme: "Eh bien, c'est un test d'intégration et nous devons tester le code séparément comme un test unitaire et, yada, yada, yada ..." C'est un cas où une explication puriste des pratiques contre la réalité se perd. Je rencontre parfois cela et si je ne peux pas défendre le raisonnement derrière le code de test unitaire qui repose finalement sur des dépendances externes, alors je ne peux pas le justifier.
Toute aide sur cette question est grandement appréciée, merci!
la source
Réponses:
Les tests unitaires et les tests d'intégration ont des objectifs différents.
Les tests unitaires vérifient la fonctionnalité de votre code ... que vous obtenez ce que vous attendez de la méthode lorsque vous l'appelez. Les tests d'intégration testent le comportement du code lorsqu'il est combiné en tant que système. Vous ne vous attendriez pas à ce que des tests unitaires évaluent le comportement du système, ni à des tests d'intégration pour vérifier des sorties spécifiques d'une méthode particulière.
Les tests unitaires, lorsqu'ils sont effectués correctement, sont plus faciles à configurer que les tests d'intégration. Si vous vous fiez uniquement aux tests d'intégration, vos tests vont:
Bottom line: Utiliser les tests d'intégration pour vérifier que les connexions entre les objets fonctionnent correctement, mais se pencher sur les tests unitaires d' abord pour vérifier les exigences fonctionnelles.
Cela dit, vous n'aurez peut-être pas besoin de tests unitaires pour certaines méthodes de référentiel. Les tests unitaires ne doivent pas être effectués sur des méthodes triviales ; si tout ce que vous faites est de passer par une demande d'objet au code généré par ORM et de retourner un résultat, vous n'avez pas besoin de le tester unitaire, dans la plupart des cas; un test d'intégration est suffisant.
la source
Je suis du côté des pragmatiques. Ne testez pas votre code deux fois.
Nous écrivons uniquement des tests d'intégration pour nos référentiels. Ces tests ne dépendent que d'une configuration de test simple qui s'exécute sur une base de données en mémoire. Je pense qu'ils fournissent tout ce qu'un test unitaire fait, et plus encore.
la source
Les tests unitaires offrent un niveau de modularité que les tests d'intégration (par conception) ne peuvent pas. Lorsqu'un système est refactorisé ou recomposé (et cela se produira), les tests unitaires peuvent souvent être réutilisés, tandis que les tests d'intégration doivent souvent être réécrits. Les tests d'intégration qui essaient de faire le travail de quelque chose qui devrait être dans un test unitaire en font souvent trop, ce qui les rend difficiles à maintenir.
De plus, l'inclusion de tests unitaires présente les avantages suivants:
Il est possible de diviser votre travail (et d'appliquer une approche DRY) tout en utilisant les tests unitaires et d'intégration. Comptez simplement sur des tests unitaires pour de petites unités de fonctionnalité et ne répétez aucune logique qui est déjà dans un test unitaire dans un test d'intégration. Cela entraînera souvent moins de travail (et donc moins de reprise).
la source
Les tests sont utiles lorsqu'ils se cassent: de manière proactive ou réactive.
Les tests unitaires sont proactifs et peuvent être une vérification fonctionnelle continue tandis que les tests d'intégration sont réactifs sur des données par étapes / fausses.
Si le système considéré est plus proche / dépend des données que de la logique de calcul, les tests d'intégration devraient avoir plus d'importance.
Par exemple, si nous construisons un système ETL, les tests les plus pertinents porteront sur les données (mises en scène, truquées ou en direct). Le même système aura quelques tests unitaires, mais uniquement autour de la validation, du filtrage, etc.
Le modèle de référentiel ne doit pas avoir de logique de calcul ou métier. Il est très proche de la base de données. Mais le référentiel est également proche de la logique métier qui l'utilise. Il s'agit donc de trouver un ÉQUILIBRE.
Les tests unitaires peuvent tester le comportement du référentiel. Les tests d'intégration peuvent tester CE QUI EST VRAIMENT ARRIVÉ lors de l'appel du référentiel.
Maintenant, "CE QUI EST VRAIMENT ARRIVÉ" peut sembler très attrayant. Mais cela pourrait être très coûteux pour une exécution cohérente et répétée. La définition classique des tests de fragilité s'applique ici.
Donc, la plupart du temps, je trouve juste assez bon pour écrire un test unitaire sur un objet qui utilise le référentiel. De cette façon, nous testons si la méthode de dépôt appropriée a été appelée et si les résultats Mocked appropriés sont renvoyés.
la source
Il y a 3 choses distinctes qui doivent être testées: la procédure stockée, le code qui appelle la procédure stockée (c'est-à-dire votre classe de référentiel) et le consommateur. Le travail du référentiel consiste à générer une requête et à convertir l'ensemble de données renvoyé en objet de domaine. Il y a suffisamment de code pour prendre en charge les tests unitaires qui se distinguent de l'exécution réelle de la requête et de la création de l'ensemble de données.
Donc (ceci est un exemple très très simplifié):
Ensuite, lors du test
OrderRepository
, passez un simuléISqlExecutor
et vérifiez que l'objet sous test réussit dans le SQL correct (c'est son travail) et retourne unOrder
objet approprié étant donné un ensemble de données de résultat (également simulé). La seule façon de tester laSqlExecutor
classe concrète est probablement avec des tests d'intégration, c'est juste, mais c'est une classe à enveloppe mince et elle changera rarement, donc c'est très important.Vous devez également tester également vos procédures stockées.
la source
Je peux réduire cela à une ligne de pensée très simple: favoriser les tests unitaires car cela aide à localiser les bogues. Et cela de manière cohérente car les incohérences provoquent de la confusion.
D'autres raisons découlent des mêmes règles qui guident le développement OO puisqu'elles s'appliquent également aux tests. Par exemple, le principe de responsabilité unique.
Si certains tests unitaires semblent ne pas valoir la peine, alors c'est peut-être un signe que le sujet ne vaut vraiment pas la peine. Ou peut-être que sa fonctionnalité est plus abstraite que son homologue, et les tests pour elle (ainsi que son code) peuvent être abstraits à un niveau supérieur.
Comme pour tout, il y a des exceptions. Et la programmation est encore un peu une forme d'art, donc de nombreux problèmes sont suffisamment différents pour justifier l'évaluation de chacun pour la meilleure approche.
la source