Fermer

février 11, 2021

Comment tester des applications C # existantes? Facile: avec un outil de simulation


Utiliser un outil de simulation pour écrire les tests unitaires requis pour votre application C # existante est une tâche facile avec JustMock.

StackOverflow est probablement la communauté de développeurs la plus grande et la plus connue, n'est-ce pas? Et voici une question aléatoire avec 23K vues (et ce n'est pas la seule concernant ce sujet délicat):

Les tests unitaires peuvent-ils être ajoutés avec succès dans un projet de production existant?
Si oui, comment et en vaut-il la peine ?

Longue histoire courte – oui et ça vaut vraiment le coup. En ce qui concerne le «comment», prenez votre temps et lisez la suite.

Si vous vous trouvez exactement dans la même position et que vous vous posez la question ci-dessus, bienvenue au bon endroit! Pas de soucis, il existe un remède. Et vous n'avez même pas besoin de monter une colline trop raide pour cela.

J'ai déjà choisi ma «victime» pour notre petite expérience. Il s’appelle ERP et fait partie de l’interface utilisateur de Telerik pour les exemples d’applications WPF . Vous pouvez le consulter ici et télécharger son code source en suivant les étapes de l'article Télécharger les fichiers produit . Pour faire court, vous avez besoin d'un compte Telerik et du zip avant le dernier de la capture d'écran suivante:

 Compte d'essai Telerik "title =" Compte d'essai Telerik "/></p data-recalc-dims=

Je suis heureux que nous ayons réglé ce qui précède, nous peut continuer avec la vraie affaire maintenant. Prêt? Je suis prêt.

Pourquoi utiliser un outil de simulation?

Ecrire une série complète de tests unitaires prend certainement du temps. Même un simple si avec une ligne de code et une condition booléenne nécessiterait au moins deux tests pour couvrir les résultats possibles (un pour vrai et un pour faux). Imaginez ce que serait si les lignes de code et les conditions étaient plus d'un. Oui, tout cela dégénérerait rapidement assez . 😂

Avez-vous entendu parler de moquerie?

La moquerie est un processus utilisé dans les tests unitaires pour simuler des dépendances externes.

Kurzgesagt (aka en anglais, en un mot), la moquerie est un concept de test unitaire où des objets réels sont remplacés par de faux objets e à imiter le comportement des vrais. Il est fait pour qu'un test puisse se concentrer sur le code testé et non sur le comportement ou l'état des dépendances externes.

Bien sûr, ces faux objets (ou simulés) peuvent être créés et gérés manuellement. Faire tout cela seul pourrait vous coûter des tonnes de temps et être finalement improductif (et parfois ennuyeux 🤫). Oh, et n'oublions pas le cas où le code de votre application est si complexe que vous devez soit faire un refactoring majeur, soit (pire encore) le réécrire complètement à partir de zéro.

C'est pourquoi je suggérerais d'utiliser un cadre moqueur . Surtout quand on parle d'applications écrites sans la moindre idée de couverture avec des tests unitaires.

Qu'est-ce qu'un cadre moqueur?

Les frameworks moqueurs sont utilisés pour générer des objets de remplacement tels que Stubs et Mocks. Les frameworks moqueurs complètent les frameworks de test unitaire en isolant les dépendances, mais ne remplacent pas les frameworks de test unitaire. En isolant les dépendances, ils aident le processus de test unitaire et aident les développeurs à écrire des tests unitaires plus ciblés et concis. Les tests sont également plus rapides en isolant véritablement le système testé.

Qu'est-ce que JustMock et pourquoi le choisir?

Actuellement, il existe sur le marché des cadres de moquerie gratuits, mais mon opinion honnête est qu'ils sont tout simplement insuffisants. La plupart des frameworks moqueurs ont des limites quant à ce qu'ils peuvent se moquer. La limitation vient de la façon dont l'objet fictif est créé, c'est-à-dire par héritage. L'objet fictif ne peut hériter que des API publiques telles que les méthodes virtuelles, les classes abstraites et les interfaces. Cette fonctionnalité peut être suffisante pour votre projet, car de nombreuses entreprises ont des projets internes dans lesquels toutes les API peuvent être publiques car elles ne seront pas utilisées par un tiers. Pourtant, si votre équipe de développement traite une logique interne, privée, des appels statiques ou une dépendance à une bibliothèque tierce, Telerik JustMock est une solution mieux adaptée. Il vous aide à faire progresser les tests unitaires des développeurs C #.

Dépenser de l'argent pour un outil complet de moquerie comme JustMock permet aux développeurs de se concentrer uniquement sur le test du système testé et d'oublier les détails moqueurs distrayants. Les objets fictifs sont créés automatiquement en mémoire lorsque les tests sont exécutés sur la base de la configuration simple du test unitaire. Il n’existe pas d’objets factices «physiques» qui doivent être conservés à mesure que le projet évolue.

Telerik JustMock est la solution de simulation la plus rapide, la plus flexible et la plus complète pour la création de tests unitaires prenant en charge Blazor, ASP.NET Core, ASP.NET MVC, ASP.NET Web Forms, .NET Core, WPF, WinForms et les aperçu de .NET 5. Et il vous aidera certainement à résoudre tous les problèmes potentiels avant d'être interrompu par le QA. 🤓 Oh, ouais!

Avec Telerik JustMock, n'importe quel développeur pouvait commencer à créer des simulacres, des sous-marins et des faux et les utiliser dans ses tests. Vous voulez savoir comment JustMock rend les tests unitaires plus concis? OK, allons-y.

Tests unitaires et JustMock – Par où commencer?

Résumons d'abord les exigences de notre expérience. Nous avons:

  • Un vrai WPF dans une application C # (l'application ERP)
  • Pas un seul test unitaire
  • Aucune idée par où commencer

Je vous suggère de jeter un œil à l'application ERP pour commencer: [19659029] Telerik UI pour WPF ERP Sample App "title =" Telerik UI pour WPF ERP Sample App "/>

Les fois où j'ai vu ou interagi avec elle se comptent sur les doigts d'une main. Mais cela ne devrait pas déranger moi, ou toi (enfin, du moins pas beaucoup).

J'ai oublié de mentionner quelque chose à propos de JustMock – il suit le modèle Arrange-Act-Assert . Le modèle AAA rend un test plus simple et plus structuré en le divisant en trois sous-sections, comme expliqué ci-dessous:

Une fois l'extension JustMock installée, vous êtes assuré d'un bon départ. Les modèles de projet qui l'accompagnent m'ont aidé à créer un projet de test en quelques secondes.

Maintenant, je suis prêt pour les tests unitaires!

Modifier / Supprimer des commandes

Voir les boutons Modifier et supprimer à gauche sous la barre d'Ariane? Je parie qu'il y a une commande liée aux deux.

Vous avez remarqué que l'élément Commandes est initialement sélectionné? Étonnamment (ou non), son DataContext est le OrdersViewModel. De retour aux commandes, oui, les voici:

this .EditRecordCommand = new DelegateCommand (

(o) =>

{

] dialogFactory.TargetItemName = this .ItemName;

dialogFactory.ShowEditDialog ( this .ItemToEdit);

this . Actualiser ();

},

(o) => this .ItemToEdit! = null );

this .DeleteRecordCommand = nouveau DelegateCommand (

(o) =>

{

dialogFactory.TargetItemName = this .ItemName;

if (dialogFactory.ShowDeleteDialog ())

{

( this .ItemToEdit as ISavableObject) .D elete ();

this .Refresh ();

}

},

(o) => this [19659038] .ItemToEdit! = null );

Voyons comment ce qui précède peut être couvert avec des tests unitaires et écrivons nos premiers avec Just Mock! Le but des deux tests – supposons qu'il existe une liaison directe entre les boutons et les commandes. De cette façon, nous pourrons tester les commandes elles-mêmes. Toutes les dépendances (par exemple, ERPDialogFactory, SalesOrderHeader, CollectionView) seront simulées et l'exécution réussie des méthodes respectives (par exemple, ShowEditDialog, ShowDeleteDialog, Refresh) sera vérifiée. En commençant par EditRecordCommand.

  

[TestMethod]

public void OrdersViewModel_EditRecordCommandExecutedS Successful ()

{[196590741]

{[196590741]

// Arrange

var dialogFactory = Mock.Create ();

var salesOrderItem = Mock.Create ();

var collectionView = Mock.Create < QueryableDataServiceCollectionView > ();

Mock.Arrange (() => new ERPDialogFactory ()). Renvoie (dialogFactory);

Mock.ArrangeSet ((( ) => dialogFactory.TargetItemName = "myItemName" );

Mock.Arrange (() => dialogFactory.ShowEditDialog (salesOrderItem)). DoNothing ();

Mock.Arrange (() => collectionView.HasChanges) .Returns ( true );

Mock.Arrange (() => collectionView.RejectChanges ()). InOrder (); [19659043] Mock. Arrange (() => collectionView.Refresh ()). InOrder ();

// Act

var viewModel = new OrdersViewModel (); [19659043] viewModel.SelectedItem = salesOrderItem;

Mock.Arrange (() => viewModel.ItemName) .Returns ( "myItemName" );

Mock .Arrange (() => viewModel.Items) .Returns (collectionView);

viewModel.EditRecordCommand.Execute ( null );

// Assert

Mock.Assert (dialogFactory);

Mock.AssertSet (() => dialogFactory.TargetItemName = "myItemName" Occurs.Once ()); [19659043] Mock.Assert (salesOrderItem);

Mock.Assert (collectionView);

}

Couvrir le DeleteRecordCommand avec un test unitaire ressemble beaucoup à celui de EditRecordCommand:

  

[TestMethod]

public void OrdersViewModel_DeleteRecordCommandExecutedS Successful ()

{

// // Arrange

var dialogFactory = Mock.Create ();

var salesOrderItem = Mock.Create ();

var collectionView = Mock.Create < QueryableDataServiceCollectionView > ();

Mock.Arrange (() => new ERPDialogFactory ()). Renvoie (dialogFactory);

Mock.ArrangeSet ((( ) => dialogFactory.TargetItemName = "myItemName" );

Mock.Arrange (() => dialogFactory.ShowDeleteDialog ()). Renvoie ( true );

Mock.Arrange (() => salesOrderItem.Delete ()). DoNothing ();

Mock.Arrange (() => collectionView.HasChanges) .Returns ( true );

[19659042] Mock.Arrange (() => collectionView.RejectChanges ()). InOrder ();

Mock.Arrange (() => collectionView.Refresh ()). InOrder ();

[19659133] // Act

var viewModel = new OrdersViewModel ();

viewModel.SelectedItem = salesOrderItem;

Mock.Arrange ( () => viewModel.ItemName) .Returns ( "myItemName" );

Mock.Arrange (() => viewModel.Items) .Returns (collectionView);

[19659042] viewModel.DeleteRecordCommand.Execute ( null );

// Assert

Mock.Assert (dialogFactory);

Mock. AssertSet (() => dialogFactory.TargetItemName = "myItemName" Occurs.Once ());

Mock.Assert (salesOrderItem);

Mock.Assert ( collectionView);

}

Imprimer ces commandes

Qu'en est-il e bouton d'impression à droite en dessous de la barre d'Ariane? Ce bouton:

< telerik: RadButton

x: Name = "Print"

local: PrintExportHelper.PrintTarget = "{Binding ElementName = gridView}"

Style = "{StaticResource GridNavigationButtonStyle}"

Largeur = "63" > [19659043] <! -

Contenu du bouton et info-bulle ici

->

</ telerik: RadButton >

Il a un ensemble PrintTarget et je suppose que c'est ce que je recherche. Voyons d'où vient ce PrintTarget et ce qu'il est censé faire. Cela semble être une propriété de dépendance, dont le setter sera appelé, et respectivement le PropertyChanged, lorsque la liaison ci-dessus est exécutée. Cela nous amène à:

private static void OnPrintTargetChanged (DependencyObject d, DependencyPropertyChangedEventArgs e)

{

var button = d as

RadButton

19659042] var gridView = e.NewValue as RadGridView;

if (button! = null && gridView! = null )

{

button.Command = new DelegateCommand (OnPrintCommandExecuted);

button.CommandParameter = gridView;

} [19659064] }

private static void OnPrintCommandExecuted ( object obj)

{

var gridView = obj ] as RadGridView;

if (gridView! = null )

{

var spread sheet = new RadSpreadsheet ();

var window = new RadWindow () {Width = 0, Height = 0, Opacity = 0, Content = spreadsheet};

window.Show ();

spreadsheet.Workbook = gridView.ExportToWorkbook ();

spreadsheet.Print ( new PrintWhatSettings (ExportWhat.ActiveSheet) , false ));

window.Close ();

}

}

Commençons cette fois par la définition XAML du bouton et tester si la liaison est correctement résolue et respectivement - cliquer sur ce bouton fait sa magie.

  

[TestMethod]

public void PrintExportHelper_PrintButtonClickExecutesPrintCommand ()

{

//

// Arrange

Mock.NonPublic.Arrange ( typeof (PrintExportHelper), "OnPrintCommandExecuted" Arg.Expr.AnyObject);

// Act

var printButton = Mock.Create ();

var args = Mock.Create ();

var gridView = Mock. Create ();

Mock.Arrange (() => args.NewValue) .Returns (gridView);

PrivateAccessor.ForType ( typeof (PrintExportHelper) )). CallMethod ( "OnPrintTargetChanged" printButton, args);

printButton.Command.Execute (gridView);

// Assert

Mock.Assert ([19659039] typeof (PrintExportHelper));

}

Ce test unitaire ne semble pas suffisamment stable. Cela garantit seulement qu'il y a un bouton d'impression et quand on clique dessus, la méthode statique de la classe d'assistance ci-dessus est appelée. Mais fonctionne-t-il correctement, c'est-à-dire que se passe-t-il exactement lorsque la commande du bouton est exécutée? Testons:

  

[TestMethod]

public void PrintExportHelper_PrintCommandExecutionSucceeded ()

{

{

//

{

// Arrange

var gridView = Mock.Create ();

Mock.NonPublic.Arrange ( typeof (PrintExportHelper), "OnPrintCommandExecuted" ]gridView);

var spreadsheet = Mock.Create ();

var workbook = Mock.Create ();

var window = Mock.Create ();

Mock.Arrange (() => window.Show ()). IgnoreInstance (). InOrder ();

Mock.Arrange (() => window.Close ()). IgnoreInstance (). InOrder ();

Mock.Arrange (() => gridView.ExportToWorkbook ());

Mock.Arrange (() => tableur.Imprimer (Arg.IsAny (), null )). IgnoreInstance ();

[19659133] // Act

PrivateAccessor.ForType ( typeof (PrintExportHelper)). CallMethod ( "OnPrintCommandExecuted" gridView);

[19659133] // Assert

Mock.Assert ( typeof (PrintExportHelper));

Mock.Assert (gridView);

Mock. Assert (window);

Mock.Assert (spreadsheet);

Mock.Assert (workbook);

}

Ici, nous devons organiser trois autres choses (à part ceux du test précédent) - la fenêtre, la feuille de calcul et son classeur (ceux-ci feront la magie d'exporter les données de la grille dans le classeur d'un tableur).

L'acte que nous accomplissons appelle la méthode OnPrintCommandExecuted avec la vue de grille simulée.

La phase d'assertion garantit que toutes les dispositions ci-dessus ont été prises, y compris cette fois celles concernant la grille, la feuille de calcul et son classeur en dehors de PrintExportHelper.

C'est le chemin heureux de la fonctionnalité d'impression. Qu'en est-il du passage d'un élément, différent de la vue de grille attendue, par exemple, une chaîne vide, à la commande d'impression? Laissez-nous couvrir cela avec un test - en supposant que nous ayons passé un faux argument, l'exécution de la commande d'impression devrait échouer, non?

  

[TestMethod]

public void PrintExportHelper_PrintCommandExecutionFailed () [19659107105] {

// [19659107105] {

// Arrange

var gridView = Mock.Create ();

Mock.NonPublic.Arrange ( typeof (PrintExportHelper), "OnPrintCommandExecuted" ]gridView) .OccursNever ();

var spreadsheet = Mock.Create ();

var workbook = Mock.Create ();

[19659042] var window = Mock.Create (Constructor.NotMocked);

Mock.Arrange (() => window.Show ()). IgnoreInstance (). InOrder (). OccursNever (); [19659043] Mock.Arrange (() => window.Close ()). IgnoreInstance (). InOrder (). OccursNever ();

Mock.Arrange (() => gridView.ExportToWorkbook ( )). OccursNever ();

Mock.Arrange (() => tableur.Print (Arg.I sAny (), null )). IgnoreInstance (). OccursNever ();

// Act

PrivateAccessor.ForType ( typeof (PrintExportHelper)). CallMethod ( "OnPrintCommandExecuted" String.Empty);

// Assert

Mock.Assert ( ] typeof (PrintExportHelper));

Mock.Assert (gridView);

Mock.Assert (window);

Mock.Assert (tableur); [19659043] Mock.Assert (classeur);

}

Devinez quoi, il a fait. Pas le test. L'exécution de la commande - nous avons fait en sorte qu'aucune invocation des méthodes ci-dessus ne se soit jamais produite en agissant avec une chaîne vide au lieu de la vue de grille attendue.

 Just Mock Tests Run Results "title =" Just Mock Tests Run Results "/></p data-recalc-dims=

Eh bien, il semble que les fonctionnalités d'exportation, de suppression et d'impression fonctionnent comme prévu. Bon travail!

Et le dernier bouton de cette barre de boutons - l'exportation? Eh bien, je laisse ceci comme votre devoir JustMock. Commentaires honnêtes dans les commentaires.

Que vous:

  • Vous êtes nouveau sur Telerik JustMock - en savoir plus à ce sujet via la page produit . Il est livré avec un essai gratuit de 30 jours ]ce qui vous laisse le temps d'explorer les fonctionnalités de JustMock.
  • Vous connaissez déjà Telerik JustMock - la version R1 2021 est déjà disponible au téléchargement dans votre compte .
  • Vous voulez profiter de Conseils de Mihail Vladov sur la rédaction de tests utilisateur - téléchargez dès maintenant le livre électronique des tests unitaires .

Indépendamment de ce qui précède «Cas», n’hésitez pas à:

Essayez le dernier JustMock Now

Vous ne le regretterez pas.




Source link