存档

“测试”分类归档

Silverlight工具包单元测试

10月30日,2008 没有评论

介绍

高质量的软件开发,单元测试是非常重要的。 Silverlight工具包具有广泛的单元测试,以及良好的样本。 Silverlight工具包单元测试项目(Controls.Testing,Controls.Test.DataVisualization,Controls.Testing.Theming)使用Silverlight单元测试框架 (Microsoft.Silverlight.Testing.dll &Microsoft.VisualStudio.QualityTools.UnitTesting.Silverlight.dll)由杰夫·威尔科克斯 ,一个单元测试类库(Controls.Testing.Common.dll)的发明发明由特德Glaza。 你可以找到许多有用的信息左右Silverlight单元测试框架,MSDN代码库网站Jeff的博客 这篇文章主要谈论泰德的单元测试类释放库Silverlight工具包 ,并演示了如何在这个框架之上建立的例子,我们的单元测试。

下面是一个简化的类图,显示Controls.Testing.Common项目的一些类,和我们的单元测试的整体设计模式:

Silverlight Toolkit Unit Test Class Diagram

图1:Controls.Testing.Common类图

平行的类层次结构

从上面的类图这是很明确的,有平行的类层次结构:

  1. FrameworkElement的< - < - 的ContentControl
  2. FrameworkElementTest < - ControlTest - ContentControlTest
  3. IOverriddenFrameworkElement < - IOverriddenControl - IOverriddenContentControl

第一层次是被单元测试的控制类的继承链。

第二个层次是在相应的单元测试类继承链,并联控制被测试的类。 这种设计的原因是ContentControl的是,如果一个控制,然后ContentControlTest应测试ControlTest做的一切。 测试类设计中有一些共同的模式。 假设XXX从YYY的继承:

  • 从YYYTest XXXTest继承。 如果XXXTest不是抽象的,它被标记为[TestClass中]属性。
      [TestClass中]
     公共部分类 ExpanderTest:HeaderedContentControlTest
     { 

  • XXXTest引入了三个新的特性:DefaultXXXToTest,XXXsToTest,OverriddenXXXsToTest,并用它们来实现覆盖其基类YYYTest提出的三个属性(DefaultYYYToTest,YYYsToTest,OverriddenYYYsToTest):
     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测试<summary> / / / / / /取得了HeaderedContentControl的默认实例(或派生类型)测试/ / / </摘要> 公众覆盖 HeaderedContentControl DefaultHeaderedContentControlToTest {{DefaultExpanderToTest;}} / / / <summary> / / /获取的HeaderedContentControl的实例(或派生类型)测试/ / / </摘要> 公众覆盖的IEnumerable <HeaderedContentControl> HeaderedContentControlsToTest。得到{的回报 ExpandersToTest.OfType <HeaderedContentControl>();}} / / / <summary> / / /获取的IOverriddenContentControl的实例(或派生类型)测试/ / / </摘要> 公众覆盖的IEnumerable <IOverriddenHeaderedContentControl> OverriddenHeaderedContentControlsToTest。得到{的回报 OverriddenExpandersToTest.OfType <IOverriddenHeaderedContentControl>();}}#endregion HeaderedContentControls测试#地区扩展测试/ / / <summary>的/ / /获取一个扩展的默认实例(或派生类型)测试/ / / </摘要> 的公共虚拟,扩展DefaultExpanderToTest {{ 返回新的Expander( );}} / / / <summary> / / /获取扩展的实例(或派生类型)测试/ / / </摘要> 公共虚拟 IEnumerable的<Expander> ExpandersToTest {{ 带来回报 DefaultExpanderToTest;。 为(int i = 0;我<4; I + +){扩展扩展新的扩展{ExpandDirection =(ExpandDirection)我的IsExpanded =(I%2 == 0)}; 产量回报膨胀;}}} / / / <summary> / / /获取实例IOverriddenContentControl(或派生类型)/ / / </摘要> 公共虚拟 IEnumerable的<IOverriddenExpander> OverriddenExpandersToTest {{ 产量突破 ;}}#endregion扩展测试测试 

  • XXXTest有一个公共的构造函数,覆盖GetDependencyPropertyTest方法:
      / / / <summary>
     / / /获取依赖项属性的测试。
     / / / </摘要>
     / / / <returns>依赖项属性的测试。</>
     公众覆盖的IEnumerable <DependencyPropertyTestMethod> GetDependencyPropertyTests()
     {
         IList的<DependencyPropertyTestMethod>测试= TagInherited(的基础 GetDependencyPropertyTests()); 

  • 5月XXXTest覆盖TemplatePartsAreDefined和TemplateVisualStateAreDefined方法,如果XXX有新的控制合同定义,或修改其祖先的合同契约:
     [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 #地区的控制权合同/ / / <summary>的/ / /验证控制TemplateParts的。/ / / </摘要> [TestMethod的[说明(“验证控制TemplateParts的。”)] 公共重写的无效 TemplatePartsAreDefined(){IDictionary的< 字符串 ,类型> templateParts = DefaultControlToTest.GetType()GetTemplateParts(); Assert.AreEqual(1 templateParts.Count); Assert.AreSame(typeof运算 (切换按钮),templateParts“ExpanderButton”]);} / / / <summary> / / /验证控件的模板的视觉状态。/ / / </摘要> [TestMethod的] [说明(“验证控件的模板的视觉状态。)] 公众覆盖无效 TemplateVisualStatesAreDefined(){的IDictionary < 字符串字符串 > visualStates = DefaultControlToTest 。。GetVisualStates的GetType()(); Assert.AreEqual(12 visualStates.Count); Assert.AreEqual < 字符串 >(“CommonStates”,visualStates [“正常”]); Assert.AreEqual < 字符串 >(“CommonStates” [“鼠标悬停”]); Assert.AreEqual visualStates < 字符串 >(“CommonStates”,visualStates“压”]); Assert.AreEqual < 字符串 >(“CommonStates”,visualStates“残疾人”]); Assert.AreEqual < 字符串 >(的“FocusStates”,visualStates“聚焦”]); Assert.AreEqual < 字符串 >(的“FocusStates”,visualStates“未聚焦”]); Assert.AreEqual < 字符串 >(“ExpansionStates,visualStates”膨胀“ ]); Assert.AreEqual < 字符串 >(“ExpansionStates visualStates [”,“崩溃”]); Assert.AreEqual < 字符串 >(“ExpandDirectionStates”,visualStates [“ExpandDown的”]); Assert.AreEqual < 字符串 >(“ExpandDirectionStates “,[”ExpandUp“]); Assert.AreEqual < 字符串 >(的”ExpandDirectionStates“,visualStates”ExpandLeft“]); Assert.AreEqual < 字符串 >(”ExpandDirectionStates“,visualStates visualStates [”ExpandRight的 “]);}# endregion控制合同 

    请注意,虽然控制合同,注明与TemplateVisualState()]和[TemplatePart()]属性,而不是通过继承类层次结构在理论上。 在现实中,他们通常是通过子类重新声明基类的控制合同。 因此,我们的单元测试类把控制合同继承。

第三个层次是用户界面和事件测试:

  / / / <summary>
 / / /接口用来测试扩展的虚拟成员。
 / / / </摘要>
 公共接口 IOverriddenExpander:IOverriddenHeaderedContentControl
 {
     / / / <summary>
     / / /获取OnExpanded的测试操作。
     / / / </摘要>
     OverriddenMethod ExpandedActions {获取;}
     / / / <summary>
     / / /取得的OnCollapsed的测试操作。
     / / / </摘要>
     OverriddenMethod CollapsedActions {获取;}
 } 

其实是第四个平行的类层次结构的第三个层次,它通常与一起使用:

  1. OverriddenFrameworkElement < - OverriddenControl - OverriddenContentControl

尚未在Controls.Testing.Common实施,,但Controls.Testing OverriddenTreeView类,这是一个很好的例子来说明上面的类看起来像什么以及他们将如何被使用,如果实施。 我可以写两个重写的类层次结构的一个单独的职位,或修改此添加更多关于他们的报道。

TestBase

TestBase
图2:TestBase

 [CompilerGenerated] private static int <DefaultVisualDelayInMilliseconds>k__BackingField; // [CompilerGenerated] 私人的静态INT <DefaultVisualDelayInMilliseconds> k__BackingField; / / 公共抽象类 TestBase:SilverlightTest {/ /字段  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; } }元素的params行动[]操作); 保护内部无效TestAsync(INT visualDelay,FrameworkElement的元素的params行动[]的行动); 保护内部的无效 TestSequenceAsync <T>(IEnumerable的元素,行动<T> 的params []行动) 其中T:FrameworkElement的; 保护内部的无效 TestSequenceAsync <T>(,INT visualDelay,IEnumerable的元素,动作<T> 的params []行动),其中T:FrameworkElement保护内部无效 TestTaskAsync(FrameworkElement的元素的params行动[]行动) 保护的内部无效TestTaskAsync(INT visualDelay,FrameworkElement的元素的params行动[]的行动); / /属性 保护的内部静态诠释 DefaultVisualDelayInMilliseconds的{[CompilerGenerated]获得; [CompilerGenerated]集;}} 

TestBase包装像EnqueueCallback,EnqueueConditional,EnqueueSleep,EnqueueTestcomplete,并提供两个高层次实用功能TestAsync和TestSequenceAsync WorkItemTest方法。 每个函数都有一个重载,需要在毫秒的延迟,给可视化树的一段时间内呈现在行动之间的测试。

相关的物业单元测试

从图1的另一个清晰的格局:Control.Testing.Common类图是所有的测试类使用DependencyPropertyTest <T,P>通用类,他们引进的依赖项属性的执行单元测试。 添加单元测试依赖项属性PPP类XXX通常包括三个步骤:

  1. 定义属性类XXXTest的“DependencyPropertyTest <T,P> PPPProperty”:
      / / / <summary>
     / / /获取ExpandDirection的依赖性能测试。
     / / / </摘要>
     set; } 保护 DependencyPropertyTest <Expander, ExpandDirection> ExpandDirectionProperty {; 私人集;} 

  2. 创建PPPProperty 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 =  DependencyPropertyTest <Expander, ExpandDirection>( 这一点 ,“ExpandDirection”){= Expander.ExpandDirectionProperty,初始值=初始值,默认值= ExpandDirection.Down,OtherValues ​​=  ExpandDirection [] {ExpandDirection.Up,ExpandDirection.Left,ExpandDirection。右}的InvalidValue = 词典<ExpandDirection, TYPE> {{(ExpandDirection)(-1),typeof运算(ArgumentException)},{(ExpandDirection)4,typeof运算(ArgumentException)},{(ExpandDirection)5,typeof运算 (ArgumentException) {(ExpandDirection)500,typeof运算 (ArgumentException)},{(ExpandDirection)的诠释 MaxValue的,typeof运算(ArgumentException)},{(ExpandDirection)INT MINVALUE,typeof运算 (ArgumentException)}}}。 

  3. 这GetDependencyPropertyTests覆盖的依赖项属性添加相应的测试:
     )); 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.Add(ExpandDirectionProperty.CheckDefaultValueTest); tests.Add(ExpandDirectionProperty.ChangeClrSetterTest); tests.Add(ExpandDirectionProperty.ChangeSetValueTest); tests.Add(ExpandDirectionProperty.ClearValueResetsDefaultTest); tests.Add(ExpandDirectionProperty.InvalidValueFailsTest);测试地址(ExpandDirectionProperty.InvalidValueIsIgnoredTest); tests.Add(ExpandDirectionProperty.CanBeStyledTest); tests.Add(ExpandDirectionProperty.TemplateBindTest); tests.Add(ExpandDirectionProperty.ChangesVisualStateTest(ExpandDirection.Down,ExpandDirection.Up,“ExpandUp”));测试。新增(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); 

您还可以添加/删除/更改GetDependencyPropertyTests重写从基类继承的依赖项属性的测试:

  tests.RemoveTests(HeaderProperty.TemplateBindTest);
 tests.Add(HeaderProperty.TemplateBindTest.Bug(“TODO:在这失败在这里的原因,但没有为内容的财产调查”)); 

后已经比我预想的,所以我现在将停止在这里。 希望这有助于你了解我们的单元测试代码和创建高质量的软件。

Technorati的标签: