Archives

Archive pour Octobre 2008

Test de Silverlight Toolkit Unit

30 octobre 2008 Pas de commentaires

Présentation

Unité de test est très important pour le développement de logiciels de qualité. Le Silverlight Toolkit a des tests unitaires vaste, ainsi que de bons échantillons. Silverlight Toolkit projets de test unitaire (Controls.Testing, Controls.Test.DataVisualization, Controls.Testing.Theming) utiliser le framework Silverlight test unitaire (Microsoft.Silverlight.Testing.dll & Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll) inventé par Jeff Wilcox , et une bibliothèque de classe de test unitaire (Controls.Testing.Common.dll) inventé par Ted Glaza. Vous pouvez trouver beaucoup d'informations utiles sur Silverlight Unit Test Framework à partir de son site MSDN Code Gallery et blogue de Jeff . Ce message parle surtout de la bibliothèque de Ted unité de test de classe publié dans le Silverlight Toolkit , et démontre par des exemples comment nos tests unitaires sont construits au-dessus de ce cadre.

Ci-dessous un diagramme de classes simplifié, montrant certaines des classes dans le projet de Controls.Testing.Common, et le modèle de conception d'ensemble de nos tests unitaires:

Silverlight Toolkit Unit Test Class Diagram

Figure 1: Diagramme de classes Controls.Testing.Common

Les hiérarchies de classe parallèle

Il est assez clair à partir du diagramme de classe ci-dessus qu'il ya des hiérarchies de classes parallèles:

  1. FrameworkElement <- <Contrôle - ContentControl
  2. FrameworkElementTest <- ControlTest <- ContentControlTest
  3. IOverriddenFrameworkElement <- IOverriddenControl <- IOverriddenContentControl

La première hiérarchie est la chaîne d'héritage de classes de contrôle étant l'unité testée.

La seconde hiérarchie est la chaîne d'héritage de classes de test unitaire correspondant, en parallèle des classes de contrôle à l'essai. La raison de cette conception est que si ContentControl est une configuration, puis ContentControlTest devrait tout tester ControlTest fait. Il ya quelques traits communs dans la conception de la classe de test. En supposant hérite XXX YYY partir de:

  • XXXTest hérite de YYYTest. Si XXXTest n'est pas abstrait, il est marqué avec [TestClass] attribut.
      [TestClass]
     public class partielle ExpanderTest: HeaderedContentControlTest
     { 

  • XXXTest introduit trois nouvelles propriétés: DefaultXXXToTest, XXXsToTest, OverriddenXXXsToTest, et les utiliser pour mettre en oeuvre la dérogation de trois propriétés (DefaultYYYToTest, YYYsToTest, OverriddenYYYsToTest) présenté par son YYYTest classe de base:
     public override HeaderedContentControl DefaultHeaderedContentControlToTest { get { return DefaultExpanderToTest; } } /// <summary> /// Gets instances of HeaderedContentControl (or derived types) to test. /// </summary> public override IEnumerable<HeaderedContentControl> HeaderedContentControlsToTest { get { return ExpandersToTest.OfType<HeaderedContentControl>(); } } /// <summary> /// Gets instances of IOverriddenContentControl (or derived types) to test. /// </summary> public override IEnumerable<IOverriddenHeaderedContentControl> OverriddenHeaderedContentControlsToTest { get { return OverriddenExpandersToTest.OfType<IOverriddenHeaderedContentControl>(); } } #endregion HeaderedContentControls to test #region Expanders to test /// <summary> /// Gets a default instance of Expander (or a derived type) to test. /// </summary> public virtual Expander DefaultExpanderToTest { get { return new Expander(); } } /// <summary> /// Gets instances of Expander (or derived types) to test. /// </summary> public virtual IEnumerable<Expander> ExpandersToTest { get { yield return DefaultExpanderToTest; for ( int i = 0; i < 4; i++) { Expander expander = new Expander { ExpandDirection = (ExpandDirection)i, IsExpanded = (i % 2 == 0) }; yield return expander; } } } /// <summary> /// Gets instances of IOverriddenContentControl (or derived types) to test. /// </summary> public virtual IEnumerable<IOverriddenExpander> OverriddenExpandersToTest { get { yield break ; } } #endregion Expanders to test HeaderedContentControls # region pour tester / / / <summary> / / / Obtient une instance par défaut de HeaderedContentControl (ou un type dérivé) pour tester / / / </ summary> public override HeaderedContentControl DefaultHeaderedContentControlToTest. {Get {return DefaultExpanderToTest;}} / / / <summary> / / / Obtient des instances de HeaderedContentControl (ou aux types dérivés) pour tester / / / </ summary> public override IEnumerable <HeaderedContentControl> HeaderedContentControlsToTest {get {return ExpandersToTest.OfType <HeaderedContentControl> ();}}. / / / <summary> / / / Obtient des instances de IOverriddenContentControl (ou aux types dérivés) pour tester / / / </ summary> public override IEnumerable <IOverriddenHeaderedContentControl> OverriddenHeaderedContentControlsToTest {get {return OverriddenExpandersToTest.OfType <IOverriddenHeaderedContentControl> ();}}. # endregion HeaderedContentControls à tester # region Expandeurs pour tester / / / <summary> / / / Obtient une instance par défaut de Expander (ou un type dérivé) à tester. / / / </ summary> public virtual Expander DefaultExpanderToTest {get {return new Expander ( );}} / / / <summary> / / / Obtient des instances de Expander (ou aux types dérivés) pour tester / / / </ summary> public virtual <Expander> IEnumerable ExpandersToTest {get {rendements DefaultExpanderToTest retour;. for (int i = 0; i <4; i + +) {Expander Expander expander = new {ExpandDirection = (ExpandDirection) i, = IsExpanded (i% 2 == 0)}; expandeur retour de rendement;}}} / / / <summary> / / / Obtient des instances de IOverriddenContentControl (ou types dérivés) pour tester / / / </ summary> public virtual <IOverriddenExpander> IEnumerable OverriddenExpandersToTest {get {pause rendement;}}. # endregion Expandeurs pour tester 

  • XXXTest a un constructeur public, et se substitue GetDependencyPropertyTest méthode:
      / / / <summary>
     / / / Obtenir les tests propriété de dépendance.
     / / / </ Summary>
     / / / Les tests <returns> propriété de dépendance. </ Returns>
     publique GetDependencyPropertyTests remplacer <DependencyPropertyTestMethod> IEnumerable ()
     {
         IList <DependencyPropertyTestMethod> tests = TagInherited (base GetDependencyPropertyTests ().); 

  • XXXTest peut remplace les méthodes et les TemplatePartsAreDefined TemplateVisualStateAreDefined, si XXX est défini contrat nouveau contrôle, ou modifie contrat de contrat de ses ancêtres:
     [TestMethod] [Description( "Verifies the Control's TemplateParts." )] public override void TemplatePartsAreDefined() { IDictionary< string , Type> templateParts = DefaultControlToTest.GetType().GetTemplateParts(); Assert.AreEqual(1, templateParts.Count); Assert.AreSame( typeof (ToggleButton), templateParts[ "ExpanderButton" ]); } /// <summary> /// Verify the control's template visual states. /// </summary> [TestMethod] [Description( "Verify the control's template visual states." )] public override void TemplateVisualStatesAreDefined() { IDictionary< string , string > visualStates = DefaultControlToTest.GetType().GetVisualStates(); Assert.AreEqual(12, visualStates.Count); Assert.AreEqual< string >( "CommonStates" , visualStates[ "Normal" ]); Assert.AreEqual< string >( "CommonStates" , visualStates[ "MouseOver" ]); Assert.AreEqual< string >( "CommonStates" , visualStates[ "Pressed" ]); Assert.AreEqual< string >( "CommonStates" , visualStates[ "Disabled" ]); Assert.AreEqual< string >( "FocusStates" , visualStates[ "Focused" ]); Assert.AreEqual< string >( "FocusStates" , visualStates[ "Unfocused" ]); Assert.AreEqual< string >( "ExpansionStates" , visualStates[ "Expanded" ]); Assert.AreEqual< string >( "ExpansionStates" , visualStates[ "Collapsed" ]); Assert.AreEqual< string >( "ExpandDirectionStates" , visualStates[ "ExpandDown" ]); Assert.AreEqual< string >( "ExpandDirectionStates" , visualStates[ "ExpandUp" ]); Assert.AreEqual< string >( "ExpandDirectionStates" , visualStates[ "ExpandLeft" ]); Assert.AreEqual< string >( "ExpandDirectionStates" , visualStates[ "ExpandRight" ]); } #endregion Control contract # Region du contrat de commande / / / <summary> / / / Vérifie TemplateParts du Contrôleur. / / / </ Summary> [TestMethod] [Description ("Vérifie TemplateParts du Contrôleur.")] Override void publique TemplatePartsAreDefined () {IDictionary <chaîne de Type> templateParts = DefaultControlToTest.GetType () GetTemplateParts ();. Assert.AreEqual (1, templateParts.Count); Assert.AreSame (typeof (ToggleButton), templateParts ["ExpanderButton"]);} / / / <summary> / / / Vérifiez modèle du contrôle états visuels. / / / </ summary> [TestMethod] [Description ("Vérifiez modèle du contrôle états visuels.")] override void publique TemplateVisualStatesAreDefined () {IDictionary <string, string> visualStates = DefaultControlToTest .. GetType () GetVisualStates (); Assert.AreEqual (12, visualStates.Count); Assert.AreEqual <> string ("CommonStates", visualStates ["Normal"]); Assert.AreEqual <> string ("CommonStates», visualStates ["mouseover"]); Assert.AreEqual <> string ("CommonStates", visualStates ["pressé"]); Assert.AreEqual <> string ("CommonStates", visualStates ["Désactivé"]); Assert.AreEqual < > string ("FocusStates", visualStates ["ciblée"]); Assert.AreEqual <> string ("FocusStates", visualStates [«Floues"]); Assert.AreEqual <> string ("ExpansionStates", visualStates ["élargi" ]); Assert.AreEqual <> string ("ExpansionStates", visualStates ["effondré"]); Assert.AreEqual <> string ("ExpandDirectionStates", visualStates ["ExpandDown"]); Assert.AreEqual <> string ("ExpandDirectionStates », visualStates [" ExpandUp "]); Assert.AreEqual <> string (" ExpandDirectionStates ", visualStates [" ExpandLeft "]); Assert.AreEqual <> string (" ExpandDirectionStates ", visualStates [" ExpandRight "]);} # contrat de contrôle endregion 

    S'il vous plaît noter que bien que les contrats de contrôle, annotée avec [TemplateVisualState ()] et [TemplatePart ()] attributs, ne sont pas hérités par hiérarchie de classes dans la théorie. En réalité, ils sont généralement, par le biais du contrat de contrôle sous-classe de base re-déclarant est. Donc, nos classes de test unitaire de traiter du contrat de contrôle hérité.

La hiérarchie troisième est pour les tests d'interface utilisateur et l'événement:

  / / / <summary>
 / / / Interface utilisée pour tester les membres virtuels de l'Expander.
 / / / </ Summary>
 IOverriddenExpander interface publique: IOverriddenHeaderedContentControl
 {
     / / / <summary>
     / / / Obtient les actions de test OnExpanded.
     / / / </ Summary>
     ExpandedActions OverriddenMethod {get;}
     / / / <summary>
     / / / Obtient les actions de test OnCollapsed.
     / / / </ Summary>
     CollapsedActions OverriddenMethod {get;}
 } 

Il ya effectivement une hiérarchie parallèle quatrième classe qui est habituellement utilisé avec la troisième hiérarchie ensemble:

  1. OverriddenFrameworkElement <- OverriddenControl <- OverriddenContentControl

Il n'est pas encore mis en œuvre dans Controls.Testing.Common, mais a de la classe Controls.Testing OverriddenTreeView, qui est un bon exemple pour montrer ce que les classes ci-dessus ressemblerait et comment elles seraient utilisées, si elles sont appliquées. Je peux écrire un post séparé pour les deux hiérarchies de classes surchargées, ou de modifier celui-ci d'ajouter plus de la couverture sur eux.

TestBase

TestBase
Figure 2: TestBase

 [CompilerGenerated] private static int <DefaultVisualDelayInMilliseconds>k__BackingField; // public abstract classe TestBase: SilverlightTest {/ / Fields [CompilerGenerated] private static int <DefaultVisualDelayInMilliseconds> k__BackingField; / /  TestAsync( int visualDelay, FrameworkElement element, params Action[] actions); protected internal void TestSequenceAsync<T>(IEnumerable<T> elements, params Action<T>[] actions) where T: FrameworkElement; protected internal void TestSequenceAsync<T>( int visualDelay, IEnumerable<T> elements, params Action<T>[] actions) where T: FrameworkElement; protected internal void TestTaskAsync(FrameworkElement element, params Action[] actions); protected internal void TestTaskAsync( int visualDelay, FrameworkElement element, params Action[] actions); // Properties protected internal static int DefaultVisualDelayInMilliseconds { [CompilerGenerated] get; [CompilerGenerated] set; } } élément, l'action params [] actions); interne protégé nulle TestAsync (int visualDelay, élément FrameworkElement, Action params [] actions); interne protégé nulle TestSequenceAsync <T> (IEnumerable éléments <T>, params action <T> [] actions)  T: FrameworkElement; interne protégé nulle TestSequenceAsync <T> (int visualDelay, IEnumerable éléments <T>, params action <T> [] actions)  T: FrameworkElement; protégée TestTaskAsync vide interne (élément FrameworkElement, Action params [] actions) ; protected void internes TestTaskAsync (int visualDelay, élément FrameworkElement, Action params [] actions); / / Propriétés interne protégé DefaultVisualDelayInMilliseconds static int {[CompilerGenerated] obtenir; [CompilerGenerated] réglé;}} 

TestBase enveloppements WorkItemTest méthodes comme EnqueueCallback, EnqueueConditional, EnqueueSleep, EnqueueTestcomplete, et fournir deux haut niveau d'utilité et de fonctions TestAsync TestSequenceAsync. Chaque fonction a une surcharge qui prend un retard en millisecondes, pour donner un peu de temps arborescence visuelle pour rendre entre les actions de test.

Dépendante de test unitaire de propriété

Un autre schéma clair du Figure 1: Diagramme de classe Control.Testing.Common est que toutes les classes de test utilisent DependencyPropertyTest classe <T,P> génériques pour la mise en oeuvre de tests unitaires pour les propriétés de dépendance qu'ils introduisent. Ajout de test unitaire pour la propriété de dépendance PPA de classe XXX comprend généralement trois étapes:

  1. Définir la propriété «DependencyPropertyTest <T,P> PPPProperty" dans la classe XXXTest:
      / / / <summary>
     / / / Obtient la propriété de test ExpandDirection dépendance.
     / / / </ Summary>
     set; } protégée DependencyPropertyTest <Expander, ExpandDirection> ExpandDirectionProperty {get; mis privé;} 

  2. Créer PPPProperty dans le constructeur de XXXTest:
     , "ExpandDirection" ) { Property = Expander.ExpandDirectionProperty, Initializer = initializer, DefaultValue = ExpandDirection.Down, OtherValues = new ExpandDirection[] { ExpandDirection.Up, ExpandDirection.Left, ExpandDirection.Right }, InvalidValues = new Dictionary<ExpandDirection, Type> { { (ExpandDirection)(-1), typeof (ArgumentException) }, { (ExpandDirection)4, typeof (ArgumentException) }, { (ExpandDirection)5, typeof (ArgumentException) }, { (ExpandDirection)500, typeof (ArgumentException) }, { (ExpandDirection) int .MaxValue, typeof (ArgumentException) }, { (ExpandDirection) int .MinValue, typeof (ArgumentException) } } }; ExpandDirectionProperty = new DependencyPropertyTest <Expander, ExpandDirection> (this, "ExpandDirection") {Propriété = Expander.ExpandDirectionProperty, initialiseur initialiseur =, DefaultValue = ExpandDirection.Down, OtherValues ​​= ExpandDirection nouvelle [] {ExpandDirection.Up, ExpandDirection.Left, ExpandDirection. Droite}, InvalidValues ​​= new Dictionary <ExpandDirection, <Type {{(ExpandDirection) (-1), typeof (ArgumentException)}, {(ExpandDirection) 4, typeof (ArgumentException)}, {(ExpandDirection) 5, typeof (ArgumentException) }, {(ExpandDirection) 500, typeof (ArgumentException)}, {(ExpandDirection) int MaxValue, typeof (ArgumentException)}, {(ExpandDirection) int MinValue, typeof (ArgumentException)}}}..; 

  3. Ajouter des tests appropriés pour cette propriété de dépendance dans GetDependencyPropertyTests remplacer:
     )); tests.Add(ExpandDirectionProperty.ChangesVisualStateTest(ExpandDirection.Up, ExpandDirection.Left, "ExpandLeft" )); tests.Add(ExpandDirectionProperty.ChangesVisualStateTest(ExpandDirection.Left, ExpandDirection.Right, "ExpandRight" )); tests.Add(ExpandDirectionProperty.ChangesVisualStateTest(ExpandDirection.Right, ExpandDirection.Down, "ExpandDown" )); tests.Add(ExpandDirectionProperty.SetXamlAttributeTest); tests.Add(ExpandDirectionProperty.SetXamlElementTest); / / ExpandDirectionProperty essais tests.Add (ExpandDirectionProperty.CheckDefaultValueTest); tests.Add (ExpandDirectionProperty.ChangeClrSetterTest); tests.Add (ExpandDirectionProperty.ChangeSetValueTest); tests.Add (ExpandDirectionProperty.ClearValueResetsDefaultTest); tests.Add (ExpandDirectionProperty.InvalidValueFailsTest); essais . Ajouter (ExpandDirectionProperty.InvalidValueIsIgnoredTest); tests.Add (ExpandDirectionProperty.CanBeStyledTest); tests.Add (ExpandDirectionProperty.TemplateBindTest); tests.Add (ExpandDirectionProperty.ChangesVisualStateTest (ExpandDirection.Down, ExpandDirection.Up, "ExpandUp")); tests. Ajouter (ExpandDirectionProperty.ChangesVisualStateTest (ExpandDirection.Up, ExpandDirection.Left, "ExpandLeft")); tests.Add (ExpandDirectionProperty.ChangesVisualStateTest (ExpandDirection.Left, ExpandDirection.Right, "ExpandRight")); tests.Add (ExpandDirectionProperty.ChangesVisualStateTest ( ExpandDirection.Right, ExpandDirection.Down, "ExpandDown")); tests.Add (ExpandDirectionProperty.SetXamlAttributeTest); tests.Add (ExpandDirectionProperty.SetXamlElementTest); 

Vous pouvez également ajouter / supprimer / modifier des tests pour les propriétés de dépendance héritée de classes de base dans GetDependencyPropertyTests passer outre:

  tests.RemoveTests (HeaderProperty.TemplateBindTest);
 tests.Add (HeaderProperty.TemplateBindTest.Bug ("TODO:. étudier pourquoi cette tentative échoue ici, mais pas pour la propriété Content")); 

Le poste est déjà plus que ce que j'attendais, je vais donc m'arrêter ici pour aujourd'hui. J'espère que cela vous aidera à comprendre notre code de test unitaire et créer des logiciels de qualité.