Conseils sur l’unité en test d’une application Windows Forms

J’ai écrit une application Windows Forms et je souhaite maintenant écrire quelques tests unitaires (pas exactement le développement piloté par les tests, vu que j’écris les tests après avoir été développé, mais mieux vaut tard que jamais!). Ma question est qu’avec une telle application comment écrivez-vous les tests unitaires, étant donné que presque toutes les méthodes et tous les événements sont privés? J’ai entendu parler de NUnit Forms mais j’entends de bonnes et de mauvaises choses à ce sujet. De plus, il n’y a eu aucun développement réel sur ce projet depuis un moment, donc il semble abandonné. En outre, il est généralement accepté que le projet dispose de tests unitaires adéquats si j’écrivais des scénarios de tests unitaires pour tous les événements déclenchés par un utilisateur en cliquant / appuyant sur les boutons, ou devrais-je écrire des scénarios de tests unitaires pour tous les événements? méthodes et trouver un moyen de tester mes méthodes privées?

EDIT: Ma logique métier est distincte de ma logique de présentation. Il existe 1 ou 2 méthodes publiques exposées par ma logique métier afin que le formulaire puisse y accéder. Mais qu’en est-il de toutes les méthodes privées de la logique métier?

La première chose à faire est de vous assurer que votre logique d’entreprise est bien séparée de votre formulaire. Fondamentalement, en utilisant un modèle MVC . Ensuite, vous pouvez facilement tester tout ce qui se trouve en dehors du formulaire, comme si le formulaire n’existait même pas.

Maintenant, cela pourrait encore laisser certaines fonctionnalités non testées spécifiques au formulaire. IE, le formulaire est-il connecté correctement au service? Pour cela, vous pouvez toujours envisager quelque chose comme NUnit Forms ou une autre alternative.

La clé des applications graphiques de test unitaire est de s’assurer que la quasi-totalité de la logique métier est dans une classe distincte et non dans le code.

Les modèles de conception tels que Model View Presenter et Model View Controller peuvent vous aider à concevoir un tel système.

Pour donner un exemple:

public partial class Form1 : Form, IMyView { MyPresenter Presenter; public Form1() { InitializeComponent(); Presenter = new MyPresenter(this); } public ssortingng SomeData { get { throw new NotImplementedException(); } set { MyTextBox.Text = value; } } private void button1_Click(object sender, EventArgs e) { Presenter.ChangeData(); } } public interface IMyView { ssortingng SomeData { get; set; } } public class MyPresenter { private IMyView View { get; set; } public MyPresenter(IMyView view) { View = view; View.SomeData = "test ssortingng"; } public void ChangeData() { View.SomeData = "Some changed data"; } } 

Comme vous pouvez le constater, le formulaire ne dispose que d’un code d’infrastructure. Toute votre logique se trouve dans votre classe Presenter, qui ne connaît qu’une interface d’affichage.

Si vous souhaitez tester cela à l’unité, vous pouvez utiliser un outil moqueur tel que Rhino Mocks pour simuler l’interface View et le transmettre à votre présentateur.

 [TestMethod] public void TestChangeData() { IMyView view = MockRepository.DynamickMock(); view.Stub(v => v.SomeData).PropertyBehavior(); MyPresenter presenter = new MyPresenter(view); presenter.ChangeData(); Assert.AreEqual("Some changed data", view.SomeData); } 

Vous avez quelques options.

  1. Utilisez un outil tel que Coded UI pour tester via votre interface utilisateur. Ce n’est pas une bonne option, car elle est plus lente que les tests unitaires et que les tests ont tendance à être plus fragiles.

  2. Séparez votre logique métier de votre logique de présentation. Si de nombreuses méthodes privées effectuent la logique métier dans votre interface utilisateur, vous avez étroitement associé votre logique métier à votre présentation. Commencez à les identifier et à les déplacer vers des classes séparées avec des interfaces publiques que vous pouvez tester. Lisez les principes de SOLID , qui peuvent vous aider à garder votre code faiblement couplé et testable.

Décomposez toute la logique métier dans un projet séparé et testez-le. Ou au moins déplacer toute la logique des formulaires dans des classes séparées.

Le test unitaire de la vue est assez simple avec les tests d’approbation (www.approvaltests.com ou nuget). il y a une vidéo ici: http://www.youtube.com/watch?v=hKeKBjoSfJ8

Cependant, il semble également que vous craignez de rendre une fonction par défaut ou publique afin de pouvoir tester la fonctionnalité.

Celles-ci sont généralement appelées coutures; façons d’entrer dans votre code pour les tests. et ils sont bons. Parfois, les gens confondent privé / public et sécurité, et ont peur de rendre publique une fonction privée, mais la reflection appellera l’un ou l’autre, ce qui fait que ce n’est pas vraiment sécurisé. D’autres fois, les gens s’inquiètent de l’interface API d’une classe. Mais cela ne compte que si vous avez une API publique et si vous avez une application Winform, celle-ci est probablement destinée au niveau supérieur (aucun autre consommateur ne l’appelle.)

Vous êtes le programmeur et, en tant que tel, pouvez concevoir votre code pour qu’il soit facile à tester. Cela ne signifie généralement guère plus que de changer quelques méthodes publiques et de créer quelques méthodes de connivence permettant de passer des dépendances.

Par exemple:

 buttonclick += (o,e)=> {/*somecode*/}; 

est très difficile à tester.

 private void button1_Click(object sender, EventArgs e) {/*somecode*/} 

encore difficile à tester

 public void button1_Click(object sender, EventArgs e) {/*somecode*/} 

plus facile à tester

 private void button1_Click(object sender, EventArgs e) { DoSave();} public void DoSave(){/*somecode*/} 

Vraiment facile à tester!

Cela va double si vous avez besoin d’informations de l’événement. c’est à dire.

 public void ZoomInto(int x, int y) 

Il est beaucoup plus facile de tester que l’événement de clic de souris correspondant et l’appel de relais peuvent toujours être une seule ligne ignorable.

On peut utiliser le modèle MVVM (Model – View – ViewModel) avec Reactive.UI pour créer du code WinForms testable. Pour obtenir la séparation des préoccupations vraiment besoin. Voir: Reactive.UI https://reactiveui.net/ Le principal inconvénient de l’utilisation de Winforms / MVVM / Reactive.UI est qu’il n’existe pas beaucoup d’exemples de son utilisation (pour WinForms). L’avantage, c’est qu’il est applicable à peu près à tous les environnements de bureau et à toutes les langues. Vous l’apprenez pour un, mais les principes s’appliquent à tous. Quand vous avez beaucoup de méthodes privées, ça va. IMHO: essayez d’utiliser des méthodes publiques pour démarrer un processus technique que vous souhaitez tester. Vous pouvez utiliser tell-Don’t-ask: https://martinfowler.com/bliki/TellDontAsk.html tout en maintenant toutes ces méthodes privées.

On peut aussi tester le code en conduisant l’UI mais ce n’est pas très recommandé, car les tests résultants sont (1) très fragiles, (2) plus difficiles à obtenir et IMHO, (3) ne peuvent pas être écrits à la même niveau de finesse que les tests de code purs; (4) Enfin: si vous utilisez une firebase database, vous devrez envisager de la renseigner avec des données de test et, comme votre firebase database doit être dans un état propre et bien défini avant chaque test, (5) vos tests peuvent s’exécuter encore plus lentement que votre pensée lorsque vous réinitialisez les données pour chaque test.

Résumé: Créez votre code avec un bon SoC (par exemple en appliquant MVVM), votre testabilité sera bien meilleure.