{S0}简介
在这篇文章中,我将展示如何利用用于测试的Windows Workflow Foundation(WF)。最初,微软旨在WF上描述的业务流程内一个应用程序。我们的想法是,我们可以利用这种技术来描述测试的过程以及。测试人员设计了一个测试,使用一个可视化的图表,更重要的是重要的是,他可以自动执行此测试。
阅读文章后,您将学习:如何使用Workflow Foundation的自动化测试如何自动检查测试结果如何重用您正在开发的其他测试测试如何延长Workflow Foundation来满足您特定的测试需求
为了证明所有的quot;如何Tosquot;,我创建在C TestflowFramework#和连接它的文章。我希望你有足够的知识WF和C#说"您好worldquot;剩下的东西,我会在下面解释。
使用TestflowFramework测试仪,我们可以在Visual Studio 2008设计图测试(为简便起见,我命名为"Testflow??与测试工作流程图表)。块上的Testflow"型图对应的用户,如行动,在该领域的文本??或"按一下按钮??图完成后,测试仪就可以运行它和所有的行动将自动对应用程序的模拟。
本文附带的解决方案,包含一个示例应用程序和其testflows。示例应用程序管理的用户列表。它支持查看/添加/编辑/删除用户。样品testflow执行以下操作顺序:点击"添加用户??进入"登录?? "姓名??部??领域,并依此类推。在接下来的章节中,我将解释如何重用的测试,并多次不同的参数运行。
本文主要测试Windows窗体应用程序。同样,这种方法可以扩展ASP.NET。甚至可以通过它紧凑的框架和XNA平台,但有一些额外的努力。它是如何工作
好了,Windows Workflow Foundation是一个非常强大的技术,并混合使用Visual Studio 2008使得它完全爆炸。 Workflow Foundation的一个完美在运行时和设计时的可扩展架构。
在运行时,我们需要模拟用户操作,并将其应用到Windows窗体。当前版本的TestflowFramework实现了几个活动:ClickButtonActivity,InputTextActivity,CloseFormActivity。任何人都可以延长此设置并添加一些先进的活动来操纵网格,观众等
设计时,我公司开发设计器类,调整WF的组成部分,标题的风格,并实施一些限制。特别是,任何测试行动
允许添加成FormScope活动。
FormScope活动是一个容器元素,承载任何测试活动和用品为他们的背景下。换句话说,FormScope包含行动用户可以做一个给定的表格。测试仪上图FormScope后,选择一个应用程序的现有形式。见下图:
下面的图片显示ClickButtonAction绑定AddUserForm FormScope。请注意,点击按钮被选择从一个强类型的列表,从AddUserForm通过反射读取。
这也是值得一提的是,行动仿真通过反射。这种做法利弊。首先,如果你更改分辨率,坐标,形式的布局,测试工作尽管一切,因为测试是必然形式和控制的纲领性名称。而这赋予第二个优势:当您重命名/删除控制,你会被编译器的通知(是的,在编译的时候!)。其缺点是,您可能需要制定一些控制自定义的测试活动。但奖励是一个高可靠性的测试。尽管如此,这是不是唯一的方法。某些情况下可能需要另一个(例如,如果你想测试的Win32应用程序)。为应用程序编写测试
该示例包含一个简单的用户列表的应用程序管理。它有两种形式:
正如我已经告诉上面,我们的测试是一个内部嵌套一个FormScope活动的用户操作的顺序。每个用户动作是由一个专门的活动类型。在给定版本的Testflowframework中,我已经包括了四种类型:ClickButtonActivity - 此活动点击窗体上的一个特定的按钮InputTextActivity - 这一活动类型到一个指定的测试TextBox控制项CloseFormActivity - 这项活动结束当前的形式,它是等同于单击窗口右上角的关闭按钮ReadProperty - 实际上,它并不符合用户操作直接,而不是做一些事情,它允许读取任何控件的属性
它保存到连续检查的工作流程的内部属性(下文详述的quot;验证测试Resultsquot;章)
下图显示了添加用户的样本testflow:
的
单击
在这个测试按钮,"添加Userquot;。然后登录,姓名和部门等领域都充满了指定的测试数据。并点击quot; OKquot;按钮提交最终。
现在,如果你已经掌握了这些基本原则,让我们进一步。重用测试
只要你创建了一个测试,你想用不同的参数重用。比方说,我们有"adduser的??从上面的测试。我们怎样才能创建具有不同的三个用户登录,姓名和部门?我们将使用与工作流属性绑定值的技术来完成这项任务。请参阅下面的两个步骤:
创建一个带参数的测试部分。
创建??代码> ADDUSER??活动。打开图和添加InputTextActivity。这一活动的TextBox属性,选择txtLogin和绑定inputText的工作流属性??代码>登录??见下图:
{五}
FullName和部门做同样的事情。最后,你必须有三项活动势必三个属性。重用测试的一部分,并设置其参数。
创建一个新的工作流程,从工具箱拖动- N -降"的adduser??测试。系的FullName属性登录,然后设置值。您可能会增加,因为你需要创建任意数量的用户多次测试。
{中六}
验证测试结果
在这一点上,我们的测试中创造了三个用户。至少这是由于... ...如果结果是错误的,我们如何能验证这一事实,并提醒?
好了,在给定的情况下,我们将简单地验证创建的用户数:我们将要访问的用户列表(listUsers控制在主窗体),并检查项目的数量。如果不是等于3,我们中止测试。
我已经开发出一种可重用的自定义活动ReadProperty读取任何控制的任何财产,其价值进一步检查在任何测试。在给定的情况下,我们将读取从listUsers控制Items.Count属性:
{七}
正如你可以看到,从应用程序读取数据很简单。我们应该选择控制我们的表格名称,然后我们设置此控件的属性名称。最后,我们指定的目标值的约束。所以UsersCount财产将被保存到listUsers.Items.Count价值当前工作流的类。
下一步,我们将验证这对一个约束UsersCount属性:
因此,我们检查的条件。在失败的情况下,我们甚至可以指定的原因,它会被写入日志文件。相反,如果一切顺利,形式是一个短暂的延迟后正常关闭。运行测试
目前的版本使用一个非常简单的方法测试开始。要开始测试,你需要几个命令行参数来启动应用程序,指定测试组装试验和测试的名称本身含有。
例如:WinApp.exe -test "TestflowsForWinApp.dll" AddUser_TestFlow TestLog.txt
测试完成后,其结果是写入日志:{C}
日志文件被命名为TestLog.txt存储在应用程序文件夹(例如,\ WinApp \ BIN \调试\示例应用程序)。
毫无疑问,这个简化的方法,可以详细阐述了特殊要求。日志可以保存到一个XML文件。测试发射引擎可以实现在一个更复杂的的方式。尽管如此,我让它尽可能简单,为了突出主的想法。提示不要使用标准InvokeWorkflow活动,从另一个调用一个测试。这项活动启动指定的工作流是异步的。在大多数情况下,这是意外的行为。除了大会主要测试可重复使用的测试部分放入一个单独的程序。主要测试的组装与测试部分应参照大会。在这种情况下,你会看到在"工具箱"中的测试部分,可以很容易地拖N -拖放到主测试他们。如果测试部分将在相同的程序集,Visual Studio不会显示他们在工具箱中。您可以使用标准的活动,丰富您的测试。例如,使用DelayActivity模拟用户思维。Workflow Foundation的扩展,并创建一个自定义的测试活动
现在你知道如何创建一个测试用TestflowFramework的。这是时间来学习如何设计自己的活动类型和充实新的用户操作测试。下面我们将通过创建InputTextActivity允许进入一个TextBox控件测试文本的过程中:创建一个活动类,并从WindowsControlActivity继承。public partial class InputTextActivity : WindowsControlActivity
{
}
我们可以从最普遍的活动类继承,但WindowsControlActivity我们提供了一些测试活动所需的基本功能。声明TextBox属性。
据Workflow Foundation的范式,属性应该被宣布为一种特殊的方式如下所示:public static readonly DependencyProperty TextBoxProperty =
DependencyProperty.Register(
"TextBox",
typeof(string),
typeof(InputTextActivity),
new PropertyMetadata(
"",
DependencyPropertyOptions.Metadata,
new Attribute[]
{ new ValidationOptionAttribute(ValidationOption.Required) }
)
);
[DefaultValue(""),
Description("TextBox where the text will be typed"),
RefreshProperties(RefreshProperties.All),
MergableProperty(false),
TypeConverter(typeof(ControlTypeConverter)),
Category("Testing")]
public string TextBox
{
get
{
return (base.GetValue(TextBoxProperty) as string);
}
set
{
base.SetValue(TextBoxProperty, value);
}
}
每个属性应当伴随着一个的DependencyProperty类型的静态字段。此领域发挥元数据容器中的作用,并帮助Windows工作流为我们做了许多有用的服务。
你也可以注意的TypeConverter(typeof运算(ControlTypeConverter))属性。这是一个很重要的一点,延长设计时行为。ControlTypeConverter开始工作时,我们的活动是图上选择,用户尝试在属性窗口中设置TextBox属性的值。实现类型转换器。
类型转换器提供了一个值列表的设计者和用户可以从下拉列表中选择其中之一。 ControlTypeConverter是一个非常简单的类你可以看到在下面的代码片段:protected class ControlTypeConverter : TypeConverter
{
// Methods
public ControlTypeConverter()
{ }
public override TypeConverter.StandardValuesCollection
GetStandardValues(ITypeDescriptorContext context)
{
IControlFieldProvider provider = null;
object[] instance = context.Instance as object[];
if ((instance != null) && (instance.Length > 0))
{
provider = instance[0] as IControlFieldProvider;
}
else
{
provider = context.Instance as IControlFieldProvider;
}
ICollection values = new object[0];
if (provider != null)
{
values = provider.GetPropertyValues(context);
}
return new TypeConverter.StandardValuesCollection(values);
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{ return true; }
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{ return true; }
}
类型转换器中使用的接口IControlFieldProvider,是实施中的WindowsControlActivity类。它读取所有的表单域,通过反思。然后,它把值列表字段的名称,如果它有一个控制的类型:protected Type filterType = typeof(Control);
ICollection IControlFieldProvider.GetPropertyValues(ITypeDescriptorContext context)
{
StringCollection strings = new StringCollection();
if (this.FormType != null)
{
BindingFlags flags =
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.GetField;
foreach (FieldInfo info in this.FormType.GetFields(flags))
{
if (!info.IsSpecialName)
{
if (info.FieldType == filterType || info.FieldType.IsSubclassOf(filterType))
strings.Add(info.Name);
}
}
}
return strings;
}
坚持这种模式,你可以申报任何财产,任何预定义的值。声明inputText的属性。
现在是时候移动到第二个属性的inputText。此属性不具有预定义的值,并可能接受任何字符串值。但它有另一个有用的功能:它是可绑定的。首先,我们已经准备绑定属性的基础设施。要做到这一点,我们声明一个特殊的属性:public static readonly DependencyProperty ParametersProperty =
DependencyProperty.Register(
"Parameters",
typeof(WorkflowParameterBindingCollection),
typeof(InputTextActivity),
new PropertyMetadata(
DependencyPropertyOptions.Metadata |
DependencyPropertyOptions.ReadOnly
)
);
public WorkflowParameterBindingCollection Parameters
{
get
{
return ((WorkflowParameterBindingCollection)
(base.GetValue(ParametersProperty)));
}
}
...并在构造函数初始化它与下面的行:base.SetReadOnlyPropertyValue(ParametersProperty,
new WorkflowParameterBindingCollection(this));
绑定的基础设施已准备就绪。财产申报:
实现运行时的行为。public static DependencyProperty InputTextProperty =
DependencyProperty.Register(
"InputText",
typeof(string),
typeof(InputTextActivity)
);
[Description("Text entered into the text box")]
[Category("Testing")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string InputText
{
get
{
return ((string)(base.GetValue(InputTextProperty)));
}
set
{
base.SetValue(InputTextProperty, value);
}
}
好了,这一点是非常简单的。在一般情况下,我们将覆盖标准的执行方法。但它已经做了在父类WindowsControlActivity。这个类执行一些准备在测试过程中的正常工作与Windows控件所需的例程。它还定义的DoControlActivity方法应由继承人覆盖。而我们这样做:protected override void DoControlActivity(Form form)
{
TextBox box = GetControl(form, TextBox) as TextBox;
box.Select();
box.Text = InputText;
}
我们的测试活动选择指定的TextBox和quot; typesquot,有文字。底线
恭喜!我们已经扩展了工作流程的基础,并提出我们的测试活动的工作。
我们宣布从WindowsControlActivity继承一个类(或活动)。然后,我们宣布了两个属性:第一个预定义的控制清单第二个是一个可绑定的字符串属性。所有申报,由永丰需要一个特定的模式。最后,我们定义了运行时的行为,通过覆盖DoControlActivity的方法(或Execute方法,如果我们需要做的事情一般)。