Silverlight Toolkit Unit Test
Einführung
Unit-Test ist sehr wichtig für die Qualität der Softwareentwicklung. Das Silverlight Toolkit verfügt über umfangreiche Unit-Tests, sowie gute Beispiele. Silverlight Toolkit Unit-Test-Projekten (Controls.Testing, Controls.Test.DataVisualization, Controls.Testing.Theming) nutzen die Silverlight Unit Test Framework (Microsoft.Silverlight.Testing.dll & Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll) durch erfand Jeff Wilcox , und ein Unit-Test-Klassenbibliothek (Controls.Testing.Common.dll) von Ted Glaza erfunden. Hier finden Sie viele hilfreiche Informationen über Silverlight Unit Test Framework von seiner MSDN Code Gallery-Site und Jeff Blog . Dieser Beitrag vor allem Gespräche über Teds Unit-Test-Klassenbibliothek in der veröffentlichten Silverlight Toolkit , und zeigt anhand von Beispielen, wie unsere Unit-Tests auf der Oberseite des Rahmens gebaut werden.
Unten ist eine vereinfachte Klassendiagramm zeigt einige der Klassen in Controls.Testing.Common Projekt und das gesamte Design-Muster unseres Unit-Tests:
Abbildung 1: Controls.Testing.Common Klassendiagramm
Parallel Klassenhierarchien
Es ist ziemlich klar, von oben Klassendiagramm, dass es parallel Klassenhierarchien:
- FrameworkElement <- Control <- ContentControl
- FrameworkElementTest <- ControlTest <- ContentControlTest
- IOverriddenFrameworkElement <- IOverriddenControl <- IOverriddenContentControl
Die erste Hierarchie ist das Erbteil Kontrollkette Klassen, die als Einheit getestet.
Die zweite Hierarchie ist die Vererbung Kette der entsprechenden Unit-Test-Klassen, parallel zur Kontrolle Klassen getestet. Der Grund für diese Konstruktion ist, dass, wenn ContentControl ist eine Kontrolle, dann sollte alles ContentControlTest ControlTest nicht testen. Es gibt einige gemeinsame Muster in Testklasse entwerfen. Unter der Annahme, XXX erbt von YYY:
- XXXTest erbt von YYYTest. Wenn XXXTest ist nicht abstrakt, ist es mit [TestClass]-Attribut gekennzeichnet.
[TestClass] public partial class ExpanderTest: HeaderedContentControlTest {
- XXXTest stellt drei neue Eigenschaften: DefaultXXXToTest, XXXsToTest, OverriddenXXXsToTest und nutzen sie, um die Überschreibung der drei Eigenschaften (DefaultYYYToTest, YYYsToTest, OverriddenYYYsToTest) von seiner Basisklasse YYYTest eingeführt umzusetzen:
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 # Region HeaderedContentControls zu / / / <summary> test / / / Ruft eine Standardinstanz von HeaderedContentControl (oder einem abgeleiteten Typ) zu testen / / / </ summary> public override HeaderedContentControl DefaultHeaderedContentControlToTest. {Get {return DefaultExpanderToTest;}} / / / <summary> / / / Ruft Instanzen HeaderedContentControl (oder abgeleiteten Typen) zu testen / / / </ summary> public override IEnumerable <HeaderedContentControl> HeaderedContentControlsToTest {get {return ExpandersToTest.OfType <HeaderedContentControl> ();}}. / / / <summary> / / / Ruft Instanzen IOverriddenContentControl (oder abgeleiteten Typen) zu testen / / / </ summary> public override IEnumerable <IOverriddenHeaderedContentControl> OverriddenHeaderedContentControlsToTest {get {return OverriddenExpandersToTest.OfType <IOverriddenHeaderedContentControl> ();}}. # endregion HeaderedContentControls auf # test Region Expander zu / / / <summary> test / / / Ruft eine Standardinstanz von Expander (oder einem abgeleiteten Typ) zu testen. / / / </ summary> public virtual Expander DefaultExpanderToTest {get {return new Expander ( );}} / / / summary / / / Ruft Instanzen Expander (oder abgeleiteten Typen) zu testen / / / </ 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 / / / Ruft Instanzen IOverriddenContentControl (oder abgeleiteten Typen) zu testen / / / </ summary> public virtual IEnumerable <IOverriddenExpander> OverriddenExpandersToTest {get {yield break;}}. # endregion Expander zu testen
- XXXTest hat einen öffentlichen Konstruktor, und überschreibt GetDependencyPropertyTest Methode:
/ / / <summary> / / / Holen Sie sich die Abhängigkeitseigenschaft Tests. / / / </ Summary> / / / <returns> Die Abhängigkeitseigenschaft Tests. </ Returns> public override IEnumerable <DependencyPropertyTestMethod> GetDependencyPropertyTests () { IList <DependencyPropertyTestMethod> tests = TagInherited (Basis GetDependencyPropertyTests ().);
- XXXTest kann überschreibt TemplatePartsAreDefined und TemplateVisualStateAreDefined Methoden, wenn XXX neue Steuerung Vertrag definiert ist, oder ändert seine Vorfahren Vertrag Vertrag:
[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 Kontrolle Vertrag / / / summary / / / Überprüft die Control TemplateParts. / / / </ Summary> [TestMethod] [Description ("Überprüft die Control TemplateParts.")] Public override void TemplatePartsAreDefined () {IDictionary <string , Type> templateParts = DefaultControlToTest.GetType () GetTemplateParts ();. Assert.AreEqual (1, templateParts.Count); Assert.AreSame (typeof (ToggleButton), templateParts ["ExpanderButton"]);} / / / <summary> / / / Überprüfen Sie die Kontrolle der Vorlage visuellen Zustände. / / / </ summary> [TestMethod] [Description ("Überprüfen Sie die Kontrolle der Vorlage visuellen Zustände.")] 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 ["Gedrückt"]); Assert.AreEqual <string> ("CommonStates", visualStates ["Disabled"]); Assert.AreEqual < string> ("FocusStates", visualStates ["Focused"]); Assert.AreEqual <string> ("FocusStates", visualStates ["Unschärfe"]); Assert.AreEqual <string> ("ExpansionStates", visualStates ["Erweitert" ]); Assert.AreEqual <string> ("ExpansionStates", visualStates ["zusammengebrochen"]); 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 Kontrolle Vertrag
Bitte beachten Sie, dass, obwohl Kontrolle Verträge, versehen mit [TemplateVisualState ()] und [TemplatePart ()] Attribute, die nicht über Klassenhierarchie in Theorie geerbt. In Wirklichkeit sind sie in der Regel durch Unterklasse erneut erklärt Basisklasse Kontrolle Vertrag. Also unsere Unit-Test-Klassen zu behandeln Kontrolle Vertrag vererbt.
Die dritte Hierarchie ist für UI-und Event-Tests:
/ / / <summary> / / / Interface verwendet, um virtuelle Mitglieder der Expander zu testen. / / / </ Summary> public interface IOverriddenExpander: IOverriddenHeaderedContentControl { / / / <summary> / / / Ruft die OnExpanded Test Aktionen. / / / </ Summary> OverriddenMethod ExpandedActions {get;} / / / <summary> / / / Ruft die OnCollapsed Test Aktionen. / / / </ Summary> OverriddenMethod CollapsedActions {get;} }
Es ist eigentlich ein Viertel parallel Klassenhierarchie, die normalerweise mit der dritten Hierarchie zusammen verwendet:
- OverriddenFrameworkElement <- OverriddenControl <- OverriddenContentControl
Es ist noch nicht in Controls.Testing.Common umgesetzt, aber Controls.Testing hat OverriddenTreeView-Klasse, die ein gutes Beispiel zu zeigen, was über den Klassen aussehen würde und wie sie verwendet werden, wenn sie umgesetzt wird. Ich kann ein separater Beitrag für die beiden überschrieben Klassenhierarchien schreiben, oder ändern diese umfassendere Berichterstattung über sie hinzu.
TestBase
[CompilerGenerated] private static int <DefaultVisualDelayInMilliseconds>k__BackingField; // public abstract class 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; } } Element, params Action [] Aktionen); protected internal void TestAsync (int visualDelay, FrameworkElement Element, params Action [] Aktionen); protected internal void TestSequenceAsync <T> (IEnumerable-Elemente, params Aktion <T> [] Aktionen) where T: FrameworkElement; protected internal void TestSequenceAsync <T> (int visualDelay, IEnumerable-Elemente, params Aktion <T> [] Aktionen) where T: FrameworkElement; protected internal void TestTaskAsync (FrameworkElement Element, params Action [] Aktionen) ; protected internal void TestTaskAsync (int visualDelay, FrameworkElement Element, params Action [] Aktionen); / / Properties protected internal static int DefaultVisualDelayInMilliseconds {[CompilerGenerated] erhalten; [CompilerGenerated] gesetzt;}}
TestBase Wraps WorkItemTest Methoden wie EnqueueCallback, EnqueueConditional, EnqueueSleep, EnqueueTestcomplete, und stellen zwei hohen Nutzenfunktionen TestAsync und TestSequenceAsync. Jede Funktion hat eine Überladung, eine Verzögerung in Millisekunden dauert, geben visuelle Struktur einige Zeit, um in zwischen Test-Aktionen zu machen.
Abhängig Property Unit Test
Ein weiteres klares Muster aus Abbildung 1: Control.Testing.Common Klassendiagramm ist, dass alle Testklassen DependencyPropertyTest <T,P> generische Klasse zu verwenden, um die Umsetzung Unit-Test für Abhängigkeitseigenschaften sie einzuführen. Hinzufügen Unit-Test für Abhängigkeitseigenschaft PPP der Klasse XXX umfasst in der Regel in drei Schritten:
- Definieren Eigentum "DependencyPropertyTest <T,P> PPPProperty" in Klasse XXXTest:
/ / / <summary> / / / Ruft ExpandDirection Abhängigkeitseigenschaft zu testen. / / / </ Summary> set; } geschützt DependencyPropertyTest <Expander, ExpandDirection> ExpandDirectionProperty {get; privat;}
- Create PPPProperty in XXXTest Konstruktor:
, "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") {Property = Expander.ExpandDirectionProperty, Initializer = Initialisierung, DefaultValue = ExpandDirection.Down, OtherValues = new ExpandDirection [] {ExpandDirection.Up, ExpandDirection.Left, ExpandDirection. Rechts}, 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)}}}..;
- Add entsprechenden Prüfungen für diese Abhängigkeitseigenschaft in GetDependencyPropertyTests überschreiben:
)); 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 Tests tests.Add (ExpandDirectionProperty.CheckDefaultValueTest); tests.Add (ExpandDirectionProperty.ChangeClrSetterTest); tests.Add (ExpandDirectionProperty.ChangeSetValueTest); tests.Add (ExpandDirectionProperty.ClearValueResetsDefaultTest); tests.Add (ExpandDirectionProperty.InvalidValueFailsTest); Tests . Add (ExpandDirectionProperty.InvalidValueIsIgnoredTest); tests.Add (ExpandDirectionProperty.CanBeStyledTest); tests.Add (ExpandDirectionProperty.TemplateBindTest); tests.Add (ExpandDirectionProperty.ChangesVisualStateTest (ExpandDirection.Down, ExpandDirection.Up "ExpandUp")); 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);
Sie können auch hinzufügen / entfernen / ändern Tests für Abhängigkeitseigenschaften von Basisklassen in GetDependencyPropertyTests geerbte:
tests.RemoveTests (HeaderProperty.TemplateBindTest); tests.Add (HeaderProperty.TemplateBindTest.Bug ("TODO:. untersuchen, warum dies nicht hier, aber nicht für die Content-Eigenschaft"));
Die Stelle ist schon länger als ich erwartet hatte, so werde ich hier aufhören für heute. Hope this helfen zu verstehen, unsere Unit-Test-Code und erstellen hochwertige Software.








Recent Comments