Comment structurer des tests unitaires pour une application GUI en utilisant C # et NUnit

16

On m'a demandé de réaliser un petit projet parallèle pour fournir une application simple à l'un de nos clients. Normalement, je travaillerais sur du code back-end où j'aurais compris tous mes besoins de test, et je n'ai pas encore eu le plaisir douteux d'écrire des tests pour l'interface graphique, donc je ne sais pas trop comment je dois configurer le code de test et les outils pour un EXE.

Mon premier réflexe a été d'inclure simplement les tests avec le code d'application, mais cela nécessiterait de fournir un certain nombre de dépendances spécifiques aux tests, que j'ai été spécifiquement chargé de ne pas envoyer au client. Je ne suis pas non plus en mesure de retirer de l'argent pour un outil de test spécialement conçu, je dois donc utiliser les outils que j'ai à portée de main ( StoryQ , RhinoMocks et NUnit), ce qui devrait vraiment être plus que suffisant pour tester le comportement d'une application GUI simple. Donc, pour autant que je puisse voir, cela me laisse essayer de trouver un bon équilibre entre garder la conception vraiment simple ou délibérément suringénierie pour les tests. Il semble que je crée l'application avec la logique métier dans une bibliothèque distincte et que je teste la bibliothèque comme je le ferais habituellement, ou que je trouve un autre mécanisme pour me permettre d'exécuter l'exécutable sans casser des modules supplémentaires que la conception de l'application ne fait pas. vraiment besoin.

Edit:
Veuillez noter que cette question concerne la façon de structurer la relation entre NUnit et mon exécutable - par opposition à une DLL - et non pas comment séparer la présentation et la logique métier.
/Éditer

Ma question est donc:

  1. Existe-t-il une méthode spécifique / recommandée pour configurer une application graphique simple avec des tests unitaires pour me permettre de vérifier correctement l'état et le comportement, en utilisant les outils dont je dispose, et sans recourir à une ingénierie excessive?
  2. Ai-je oublié quelque chose de fondamental sur la façon dont NUnit doit être invoqué / configuré lors du test d'un EXE (par opposition à une DLL)?
  3. Pouvez-vous me fournir ou me diriger vers des exemples illustrant comment réaliser tout cela?

Je me rends compte qu'il peut y avoir plus d'une façon de le faire, donc je recherche des directives de mise en œuvre spécifiques basées sur votre expérience.

S.Robins
la source
NUnit n'est pas conçu pour tester directement les interfaces graphiques. Vous devez séparer votre couche de présentation (c'est-à-dire la vue) de vos données et la logique métier (c'est-à-dire le modèle) afin de pouvoir tester ce qui se passe dans votre vue sans utiliser la vue.
Bernard
1
@Bernard Cette question ne concerne pas la superposition d'une interface graphique pour les tests. Je superpose naturellement toutes mes applications, même les plus triviales, ce qui n'est vraiment pas un problème pour moi. J'ai édité la question pour l'adapter, et j'espère qu'elle clarifiera toutes les idées fausses. :)
S.Robins
1
Il n'y a rien de terriblement compliqué dans les tests unitaires dans les EXE. Demandez à votre DLL de test de référencer votre fichier EXE et vous êtes prêt à partir.
whatsisname

Réponses:

3

J'ai mentionné dans l'un de mes commentaires à la réponse de Simoraman que j'avais pensé à deux façons de procéder. L'une de mes options était similaire à la suggestion de Jalayn de créer un projet en double et de générer une DLL, tandis que mon autre idée était de simplement créer un lien vers les fichiers du projet où il y avait du code que je voulais tester. Bien que les deux options puissent fonctionner, elles ne sont pas idéales.

Dans le second cas, j'aurais un gâchis de dépendances d'unité à gérer à moins que je puisse vraiment démêler l'architecture pour minimiser les dépendances. C'est bien pour les petits projets, mais les plus gros pourraient facilement devenir un vrai gâchis à gérer. Ma plus grande résistance à cette option est cependant sa pure inélégance. Bien sûr que je pourraispour le faire fonctionner, mais ce faisant, je dois effectivement interrompre l'encapsulation pour tester les composants internes d'un assemblage directement via la source, plutôt que de tester les via les interfaces publiques, ce qui, à mon avis, est un grand non-non. De même, avoir un fichier de projet supplémentaire signifierait soit la duplication des efforts dans deux projets à la fois, soit la recherche d'un moyen d'ajouter automatiquement les paramètres du fichier de projet à deux fichiers à la fois, ou de ne pas oublier de copier et renommer le champ de projet à chaque fois que je construis. Cela peut être automatisé sur le serveur de build peut-être, mais serait difficile à gérer dans l'IDE. Encore une fois, cela peut fonctionner, mais c'est un kludge au mieux, et une nuisance au pire si vous vous trompez.

La meilleure façon semble être de faire comme le nom de Whatsis commenté à ma question, et d'inclure simplement l'EXE comme référence dans le projet de test. Il s'avère qu'un EXE est effectivement traité de la même manière qu'une DLL dans ce cas, et je suis en mesure d'accéder à toutes mes classes joliment superposées pour tester tout ce qui flotte sur mon bateau.

S.Robins
la source
2

Je pense que:

  • Votre code de test d'entreprise doit être dans un projet distinct, testant votre bibliothèque de codes d'entreprise.
  • Votre code de test GUI doit être dans un projet distinct, testant votre bibliothèque GUI. Maintenant, comment construire une bibliothèque GUI au lieu d'un exécutable, j'essaie d'y répondre plus tard.
  • Si vous avez un my.namespace.biz.MyClass, votre classe de test doit être my.namespace.biz.MyClassTest (ou MyClassTestCase).
  • Si vous souhaitez tester le code trouvé dans votre cible exécutable, vous devez avoir une configuration qui construit un EXE et une autre configuration qui construit une bibliothèque (DLL) qui est celle contre laquelle vous lancerez vos tests.

Ce sont les règles que j'aime suivre, que ce soit Java ou C # (sauf qu'il n'y a pas de problème EXE avec Java bien sûr :-))

Quant à la façon de configurer votre environnement de test, il me semble que vous avez au moins ces deux choix:

Utilisation de MSBuild

Créez un clone de votre fichier .proj (par exemple myproject-as-dll.proj ). Changez le OutputTypedans le fichier cloné de " EXE" en " Library". En utilisant la commande MSBuild, vous pouvez maintenant produire une bibliothèque que vous pouvez définir comme référence dans votre projet contenant des cas de test NUnit.

Cela me semble possible, mais je ne l'ai jamais utilisé aussi honnêtement, donc je ne suis pas sûr. De plus, vous n'avez peut-être pas MSBuild sur votre serveur de test d'intégration, et je ne sais pas s'il peut être séparé de Visual Studio ...

Utilisation de NAnt

Si vous n'êtes pas familier avec NAnt, vous devrez rechercher sur Google comment configurer vos builds de projet avec. Peut-être vérifiez -le , il est un peu ancien mais l'auteur a commenté les fichiers NAnt et si cela se passe d'explication ( Edit: en examinant son fichier plus en détail, je trouve son fichier de configuration extrêmement réutilisable ). Il fait également bien plus que simplement construire, car il exécute des cas de test et lance des outils de couverture de code. Maintenant, j'avoue que je n'ai jamais utilisé NAnt, contrairement à son homologue Java et père "Ant" que j'ai beaucoup utilisé mais je vois que c'est à peu près la même chose et je ne pense pas que ce soit difficile à apprendre.

Avec cet outil, vous pouvez proposer une configuration qui vous permettra de:

  • construire tous vos projets (logique métier, GUI, etc.) dans des bibliothèques distinctes
  • construisez vos projets de test
  • lancer les tests (cette partie spécifique se fait avec la tâche NUnit2 ).
  • examinez la couverture de votre code avec la tâche NCover .

Avec un peu plus de code, vous pourriez même:

  • effectuer des déploiements nocturnes sur votre serveur d'intégration
  • si NAnt est disponible sur votre serveur d'intégration, lancez des tests d'intégration nocturnes à l'aide de tâches planifiées

Tout se fait sans rien changer dans vos fichiers Visual Studio. Et, vraiment, cela ne ressemble pas à une ingénierie excessive, c'est juste un fichier. Cela peut vous prendre un, peut-être deux jours pour que tout fonctionne, mais vous aurez à mon avis une bonne configuration.

Enfin, je donnerais au client tout ce qui est nécessaire pour construire, tester et exécuter les projets. J'ai tendance à penser que cela montre votre professionnalisme et le fait que vous écrivez du code avec qualité dans votre esprit (ce qui me semble être le cas puisque vous recherchez des solutions élégantes)

Jalayn
la source
0

Ce n'est pas parce que le projet est petit (au départ) que l'architecture appropriée est une ingénierie excessive. Le fait que vous vouliez écrire des tests indique que votre projet n'est pas un hack ponctuel complètement trivial.

Vous n'avez pas mentionné le cadre graphique que vous utilisez. WPF MVVM (Model-View-ViewModel) est bon et vous permet d'écrire des tests pour toute la logique assez facilement. Avec WinForms, j'ai entendu de bonnes choses à propos de MVP (Model-View-Presenter)

simoraman
la source
J'écris des tests pour tout le code que j'écris. Même les choses que vous pourriez trouver triviales. La seule fois où je n'écris pas de test, c'est quand je pointe. Dans ce cas, j'expédie un utilitaire unique à un client, donc les tests sont plus qu'un simple luxe, c'est une exigence afin de satisfaire nos normes de qualité. En termes de "suringénierie", ce n'est pas un choix entre une bonne ou une mauvaise architecture, mais plutôt d'éviter la nécessité d'imposer des couches supplémentaires qui ne sont pas nécessaires dans ce cas, car l'application est à usage unique avec un cycle de vie relativement court.
S.Robins
En ce qui concerne le choix du gui-framework, je ne vois pas comment cela affectera la manière dont l'environnement de test est configuré. Je cherche COMMENT spécifiquement implémenter des tests unitaires pour la couche GUI en utilisant les outils dont je dispose. Cette réponse particulière ne me dit vraiment rien à ce sujet.
S.Robins
Simoraman - Si vous supprimiez le premier paragraphe plutôt critique, ce serait vers une réponse. Réparez cela et je supprimerai mon -1. @ S.Robins note que le deuxième paragraphe est pertinent - bien que ce ne soit pas une réponse complète, cela aiderait. Si votre couche GUI est mince, bien structurée et évidente, et que toute la logique métier est testée par des tests unitaires au niveau du modèle, alors il se peut que vous n'ayez pas besoin de passer par les tracas supplémentaires de tester explicitement l'interface utilisateur.
Mark Booth
1
@MarkBooth Layering n'est pas vraiment un problème. Comme le mentionne Simiraman, je peux MVP, MVVM, ou je peux construire quelque chose de plus mince encore. J'ai cependant certains éléments spécifiques à l'interface graphique qui nécessiteront des tests explicites, c'est pourquoi j'ai décidé d'écrire cela comme une question. J'ai quelques idées, et si le pire empire, je sais que je serai finalement en mesure de résoudre le problème et de rédiger une réponse moi-même. Je voulais cependant ouvrir cela à la communauté car je pensais que cela poserait une bonne question pour ProgrammersSE. ;-)
S.Robins
0

Jetez un œil à ma réponse à cette question: comment configurer MVP pour une solution Winforms?

J'ai en fait écrit un exemple d'application qui montre comment je couche et comment je teste mon interface graphique.

lire votre montage: utilisez un lanceur de test qui s'intègre à votre environnement de développement. J'utilise ReSharper.

Bryan Boettcher
la source
Merci pour la recommandation ReSharper. Ceci est un outil que j'utilise lors du développement. Malheureusement, cela n'aidera pas lors de l'exécution des tests sur le serveur de génération d'intégration. Il ne me dit pas non plus comment configurer les tests Nunit pour accéder au code dans un exe lors des tests.
S.Robins
1
Informellement, c'est le cas. L'exe n'est que la vue, qui charge le présentateur, les modèles et les modèles de vue d'une bibliothèque de classes dans le cadre du démarrage de l'application. Au moins dans ma solution, la vue est suffisamment stupide pour que nous ne la testions pas avec des tests automatisés, et que nous fassions simplement des tests d'acceptation pour nous assurer que les choses sont bien orthographiées et que les boutons sont là où ils devraient être. NUnit-tester une DLL est très facile à faire.
Bryan Boettcher
0

J'avais écrit Nunit WinForms il y a quelques années (6 ans je suppose). Une chose dont je me souviens précisément, c'est que bien que ce soit un cas de test unitaire, il agit également comme un cas de test de bout en bout. Parfois, il n'y a pas grand-chose à tester sur un frontal (un formulaire simple). Ainsi, même si vous essayez de tester l'apparition d'une boîte de message sur un clic de bouton, vous testez involontairement diverses autres méthodes à partir d'autres couches. Il y a certaines choses que vous ne pouvez pas automatiser également. L'aspect, la convivialité et la convivialité ne peuvent pas être automatisés à l'aide de tests unitaires automatisés. Vous devrez exécuter des tests manuels avant de publier.

ViSu
la source
Si votre client spécifie qu'un écran doit avoir une certaine apparence ou changer d'une certaine manière, vous devriez pouvoir tester ces éléments. La capture des spécifications en tant que tests est au cœur de la méthodologie BDD, et je n'ai jamais trouvé de situation où vous ne pouviez pas - bien que de manière créative - trouver un moyen d'automatiser un test. La vraie question est de savoir si les tests seront utiles, si l'application est suffisamment bien prise en compte pour vous permettre d'automatiser tous les tests en premier lieu, et si les tests seront rentables. Je suis d'accord cependant, que parfois ils ne le sont pas.
S.Robins