J'ai commencé à travailler sur un projet existant avec plus de 1800 tests fonctionnels / d'intégration. Ceux-ci ont été codés avec Mstest. P>
Beaucoup d'entre eux se connectent directement à la base de données SQL Server. La base de données est générée par un générateur de code qui parmi de nombreuses choses créent la base de données. La génération de la DB est lente et encombrante. p>
Ceci comme les problèmes suivants: p>
J'aimerais que les tests existants ne soient pas dépendants de telles installations, courir plus vite si possible et ne pas avoir à gérer les bases de données via le générateur de code, des chaînes de connexion jonglant, etc. P>
J'essaie de l'accomplir aussi rapidement que possible depuis que Mon premier s'il s'agissait de changer notre classe de test d'unité de base pour vous connecter à un DB SQLite qui serait créé par le générateur de code qui génère déjà la DB principale au lieu de la DB SQL Server. La sqlite pourrait ensuite être supprimée et recopiée dans le dossier de test entre chaque exécution. Cela aurait été rapide, il n'aurait pas besoin de disposer de la base de données SQL Server, en fait, si vous n'exécutez que les tests Aucune installation SQL Server n'aurait été requise. P>
Mes problèmes étaient que le code généré utilise de nombreux concepts non inclus dans SQLite; T-SQL, syntaxe spécifique SQL Server, Schemas, Procs stockés et assemblages CLR intégrés. p>
J'ai ensuite essayé SQL Server CE 4, qui comporte de nombreuses mêmes limitations que SQLite. P>
Y a-t-il des autres alternatives disponibles autres que la réécriture de la réécriture du code à compatible avec SQLite (ou CE), réécrivez les tests existants ou un système dans lequel nous entretenons 2 séparés? p>
Edits: Test de l'unité modifié sur des tests fonctionnels, clarifié certaines choses. Mettre des choses en gras.
Je conviens que ces tests ne sont pas des tests d'unité appropriés. Je suis d'accord que la moqueur aurait été belle ici. Ce que j'essaie de faire est d'essayer de réparer le désordre que je suis confronté. P>
6 Réponses :
Générer le DB ne devrait pas être si lent et encombrant. Pouvez-vous modifier votre configuration pour courir contre un DB localhost? L'installation de SQL Server sur chaque machine de chaque développeur n'est pas très gênante, et le test sera plus rapide, car vous réduirez les retards de réseau. P>
Si vous vous connectez à une base de données ou à toute autre ressource, vous êtes pas de test unitaire non em>. Un test d'unité approprié est isolé à l'unité sous test ou de votre classe. Quelque chose en dehors de l'unité testée doit être moqué. P>
Je ne suis pas un développeur .NET, je ne peux donc pas recommander le meilleur cadre / outil moqueur, mais peut-être Cette question vous pointera dans la bonne direction . p>
Vous voudrez examiner ce problème différemment. Vous n'avez aucune envie de tester la base de données elle-même, car vous devez supposer que le produit de base de données que vous utilisez fonctionne correctement. Par conséquent, il n'est pas nécessaire de tester que "$ dao-> sauvegarder ()" insère réellement un enregistrement. Ce que vous êtes probablement intéressé, c'est que la méthode Save () est appelée lorsque d'autres actions sont effectuées ou si votre DAO génère l'instruction insertion correcte. P>
Si vous devez effectuer des appels de base de données dans votre test de base, car vous ne pouvez pas vous moquer des objets effectuant des appels de base de données, vous devez refracteur. P>
Temps de savon Temps: P>
C'est pourquoi le développement axé sur les tests est si bénéfique. Être force de garder le découplage et l'isolement à l'esprit du début conduit à une meilleure conception globale, flexibilité et testabilité. P>
Je conviens que la connexion à une base de données n'est pas un test d'unité approprié. Je verrais cela comme des tests fonctionnels. En ce qui concerne la moqueur, comme je l'ai mentionné dans mes messages, je l'ai présentée pour de nouveaux tests. Le problème est le 1800 déjà là. Le refactoring tout serait extrêmement prohibitif. J'essaie de trouver une solution pour aider les tests existants qui dépendent d'avoir une DB spécifique installé sur la machine de Dev.
Pour le cadre moqueur, je ne l'avais pas mentionné dans mon poste d'origine, mais nous utilisons MOQ qui fait le travail génial.
L'un des principes principaux des tests de l'unité est que vous ne devriez pas compter sur des objets externes (systèmes de fichiers, bases de données, etc.) une stratégie commune pour traiter ces problèmes consiste à utiliser des objets simulés (j'utilise EasyMock pour Java). Si vous archivez l'architecte votre code bien (c'est-à-dire de construire un niveau d'accès à des données solide) Vous pouvez vous maigrir sur les objets responsables de la connexion à la base de données et tester le code qui s'appuie sur l'accès aux données indépendamment de la base de données. p>
Maintenant, je comprends que je parle en termes de java / objets ici, mais la plupart des langages de programmation modernes offrent un certain type de support pour la moqueur. P>
Edit - Parfois, tout ce que vous pouvez faire est de commencer avec votre propre code, code avec TDD à l'esprit et ajouter des tests rétroactivement à tout le code que vous touchez. Finalement, vous commencerez à faire un dent dans ces 1800 tests. En outre, selon le cadre de test que vous utilisez, vous pouvez envisager de faire fonctionner deux packages de tests (nouveaux et anciens) afin de pouvoir exécuter votre état élégant des tests d'art sans avoir besoin d'exécuter les anciens p>
Je comprends que nous devrions ne pas compter sur des choses extérieures. En fait, c'est la raison pour laquelle j'essaie de changer le système existant (qui existait déjà avant ma participation). Pour de nouveaux tests, j'ai commencé à utiliser le cadre MOQ et d'autres développeurs ont également commencé à l'utiliser. Mais mon problème est les 1800 tests déjà là. Les modifier pour utiliser la moqueur est une solution possible (réécrivez les tests existants dans mon poste), mais cela semble assez coûteux (sage sur le temps).
Je ressens ta douleur. J'ai travaillé sur de nombreuses applications dans lesquelles des tests unitaires n'avaient pas été effectués ou ont été faits mal. Parfois, tout ce que vous pouvez faire est de commencer avec votre propre code, code avec TDD à l'esprit et ajouter des tests rétroactivement à tout le code que vous touchez. Finalement, vous commencerez à faire un dent dans ces 1800 tests. En outre, selon le cadre de test que vous utilisez, vous pouvez envisager d'exécuter deux packages de tests (nouveaux et anciens) afin que vous puissiez exécuter votre état élégant des tests d'art sans avoir à gérer les anciens.
@ NSFYN55: Eh bien, puisque vous demandez, quand quelqu'un demande "Comment puis-je faire xyz?", une réponse qui dit "vous ne devriez pas faire xyz" ne semble pas très utile, en particulier lorsqu'il y a plusieurs façons de faire XYZ.
@Kyratressa je pense que c'est plus comme. "Comment faites-vous XYZ?" et j'ai dit "ton problème est xyz essayer wxy?". Si votre question est "Comment puis-je garder mes muffins d'être brutal lorsque j'utilise le bicarbonate de soude?" Je pense que je suis une réponse parfaitement acceptable, c'est que "le bicarbonate de soude est la cause de votre grossesse, utilise plutôt la poudre de cuisson". SheakCabal peut accorder ses tests jusqu'à ce qu'il soit bleu au visage, mais la cause fondamentale de son problème est que l'approche de son organisation est erronée. C'est un problème très courant avec le code hérité et non legacy, mais il ne s'améliorera pas avant d'arrêter, écrivez de nouveaux tests et corrigez l'ancienne mise en œuvre.
Je comprends ton point ... mais avez-vous vu la partie où il a 1800 b> tests? À ce moment-là, la réécriture n'est vraiment pas une option.
Ouais mais dans mon expérience 1800 tests écrits mal équitables à ~ 0 tests unitaires. C'est pourquoi j'ai fait un addendum à ma réponse. Écrivez votre code avec de bonnes pratiques TDD et réécrivez les tests de tout le code que vous touchez lors de l'élimination des tests d'unité anciens. Vous serez surpris de voir à quel point les tests de merde Fast 1800 disparaîtront si tout le monde sur une équipe réécrit 10 par jour. Sur mon dernier projet moi-même et un autre développeur étaient responsables de 12 000 lignes de code + test (150 tests) dans une sprint de deux semaines.
Au lieu de supprimer et de recréer la base de données entre chaque test de test, que diriez-vous de gérer simplement chaque test dans une transaction afin que les modifications ne persistent pas?
Enveloppez chaque test dans un System.Transactions.Transactionscope , qui roule automatiquement lorsque vous avez terminé. (Si vous le souhaitez pas em> à rouler, vous affecteriez des transactions à une variable puis appelle complète () sur elle.) P> [Transaction(TransactionOption.RequiresNew)]
public void MyTestMethod()
{
// do your database tests here
// rolls back when you're done (or so I hear)
}
J'ai utilisé cette approche pour des tests d'intégration et cela fonctionne bien.
Comment l'utiliser dans MVC4?
Vous pouvez créer un instantané de base de données avant chaque test et restaurer la base de données après. La création et la restauration des instantanés est une opération plus claire que la sauvegarde / la restauration ou la reconstruction de la base de données entièrement à restaurer après votre exécution de test: p> comme une note supplémentaire: strong> Les tests d'unité d'exécution sur un niveau de données moqueur ne sont pas Un substitut à la gestion de vos tests sur une «vraie base de données». De nombreux effets «frappeurs» ne sont pas visibles de l'extérieur de votre base de données. (déclencheurs / par défaut / autorisations / disponibilité des ressources).
Pour des cas de test plus rapides et pour produire un code plus pluggable, veuillez vous moquer de votre niveau de données. Mais éventuellement, vous devrez exécuter vos cas de test sur une "vraie" base de données. Em> p> p>
La réponse acceptée semble avoir de petites problèmes de syntaxe. Il semble que le nom logique de la base de données ait besoin de correspondre au nom de la base de données et, étant donné que mon nom de base de données s'était tiré, je devais également envelopper les noms de base de données dans les bretelles carrées:
CREATE DATABASE [myDb_snapshot] ON ( NAME = [myDb], FILENAME = 'C:\MSSQL\Data\myDb_snapshot.ss' ) AS SNAPSHOT OF [myDb];
Je vous suggère de renommer vos tests «Unité» aux tests d'intégration pour éviter de nombreux Snarking
@Artarbristol: Excellente idée, j'ai édité mon poste et modifié l'unité sur fonctionnel / intégration. Mettez des choses en gras que certaines affiches semblaient avoir manqué et ajouté quelques éclaircissements.