本文通过举例说明在WF4.0中如何进行单元测试。

1、简单的WF4.0活动测试

如果是一个简单的WF4.0活动,是那种没有带BookMark,也不是messaging活动,也不是长时间运行的活动。使用WorkflowInvoker进行单元测试将非常的方便。

下面,我们以一种情况为例子:流程中只包含了两个加数相加的操作,然后就将结果返回。流程如下图所示:

最简单的方法是通过Workflow Invoker进行测试。

[TestMethod]
publicvoid ShouldAddGoodSum()
{
var output = WorkflowInvoker.Invoke(new GoodSum() {x=1, y=2});

Assert.AreEqual(3, output["sum"]);
}

如果这个测试通过,就是说这个流程的输出参数集合中包含一个 Int32的sum参数,值等于3。有下面几种情况可能需要我们进行测试

1、没有名为sum这个输出参数

2、有一个sum输出参数,但是类型不是Int32

3、有一个sum输出参数,类型也是Int32,但是值不是我们期待的(3)。

这样我们能清楚流程哪出了问题。我们修改一下流程,将输出的参数sum改成Sum。在VB中,没有什么问题,但是在C#中sum!=Sum。通过上面测试代码你会得到下面的错误提示。

但是异常信息提示的太简单,我们不知道到底是那个参数出现了问题。有更好的办法吗?有,使用WorklowTestHelper。

使用WorklowTestHelper进行单元测试

1、下载WorkflowTestHelper

2、添加WorkflowTestHelper引用

3、使用WorkflowTestHelper表达式

我们将测试代码改成:

代码

[TestMethod]
publicvoid ShouldAddGoodSumAssertOutArgument()
{
var output = WorkflowInvoker.Invoke(new GoodSum() { x =1, y =2 });

AssertOutArgument.AreEqual(output, "sum", 3);
}

再看下出现的异常信息。信息更加明确了。

AssertOutArgument.AreEqual failed. Output does not contain an argument named <sum>.

如果类型错误,例如我们将流程中的sum修改成string。

对于Assert.AreEqual我们得到下面错误提示:

Assert.AreEqual failed. Expected:<3 (System.Int32)>. Actual:<3 (System.String)>.

使用AssertOutArgument,将会得到更确切的错误信息:

AssertOutArgument.AreEqual failed. Wrong type for OutArgument <sum>. Expected Type: <System.Int32>. Actual Type: <System.String>.

2、对带有BookMark的流程进行测试

什么是BookMark?如果你有使用WF4.0开发过,就应该知道BookMark在WF中的地位。简单的说:如果你的流程需要数据,这些参数可能来自用户输入,可能来自宿主环境,BookMark是用来暂停流程,等待响应的。下面是一个书签活动的代码:

代码

publicsealedclass ReadLine : NativeActivity<string>
{
private BookmarkCallback _readCompleteCallback;

[RequiredArgument]
public InArgument<string> BookmarkName { get; set; }

protectedoverridebool CanInduceIdle
{
get { returntrue; }
}

public BookmarkCallback ReadCompleteCallback
{
get { return _readCompleteCallback ?? (_readCompleteCallback =new BookmarkCallback(OnReadComplete)); }
}

protectedoverridevoid Execute(NativeActivityContext context)
{
// Inform the host that this activity needs data and wait for the callback
context.CreateBookmark(BookmarkName.Get(context), ReadCompleteCallback);
}

privatevoid OnReadComplete(NativeActivityContext context, Bookmark bookmark, object state)
{
// Store the value returned by the host
context.SetValue(Result, state asstring);
}
}

下面我在流程中使用这个活动,用来等待用户的输入。

对于这个流程,如果你使用WorkflowInvoker,你的应用程序将会一直被挂起。所以你不得不使用WorkflowApplication,以及在你应用程序中处理这些BookMark。

如何测试这个流程。

测试这个流程将非常棘手。使用WorkflowTestHelper类库中的类将会方便很多。这个类就是WorkflowApplicationTest<T>.。这个类可以方便的创建和管理WorkflowApplication。使用非常简单的代码就可以处理好流程的所有的事件和结果。测试代码如下:

代码

[TestMethod]
publicvoid ShouldOutputGreeting()
{
// Arrange
conststring expectedFirstName ="Test";
conststring expectedLastName ="User";
var expectedGreeting =string.Format("Hello {0} {1}", expectedFirstName, expectedLastName);
var sut = WorkflowApplicationTest.Create(new TestReadLine());

// Act

// Run the workflow
sut.TestActivity();

// Wait for the first idle event - prompt for First Name
// will return false if the activity does not go idle within the
// timeout (default 1 sec)
Assert.IsTrue(sut.WaitForIdleEvent());

// Should have a bookmark named "FirstName"
Assert.IsTrue(sut.Bookmarks.Contains("FirstName"));

Assert.AreEqual(BookmarkResumptionResult.Success,
sut.TestWorkflowApplication.ResumeBookmark("FirstName", expectedFirstName));

// Wait for the second idle event - prompt for Last Name
Assert.IsTrue(sut.WaitForIdleEvent());

// Should have a bookmark named "LastName"
Assert.IsTrue(sut.Bookmarks.Contains("LastName"));

Assert.AreEqual(BookmarkResumptionResult.Success,
sut.TestWorkflowApplication.ResumeBookmark("LastName", expectedLastName));

// Wait for the workflow to complete
Assert.IsTrue(sut.WaitForCompletedEvent());

// Assert
// WorkflowApplicationTest.TextLines returns an array of strings
// that contains strings written by the WriteLine activity
Assert.AreEqual(4, sut.TextLines.Length);
Assert.AreEqual(expectedGreeting, sut.TextLines[2]);
}

3、测试WorkflowService

测试例子:

定义一个扩展类,用来存储数据和计算平均数:

1 publicclass AverageExtension
2 {
3 privatestaticreadonly List<int> Numbers =new List<int>();
4
5 publicstaticvoid Reset()
6 {
7 Numbers.Clear();
8 }
9
10 publicvoid StoreNumber(int num)
11 {
12 Numbers.Add(num);
13 }
14
15 publicdouble GetAverage()
16 {
17 return Numbers.Average();
18 }
19 }

定义一个活动使用此扩展类,在这个自定义的活动中,重写CacheMetadata方法,实现当服务中没有此扩展就添加此扩展。

代码

publicsealedclass GetAverage : CodeActivity<string>
{
public InArgument<int> Number { get; set; }

protectedoverridevoid CacheMetadata(CodeActivityMetadata metadata)
{
// This activity requires the average extension
metadata.RequireExtension(typeof (AverageExtension));

// This lambda will create one if it is not already added
metadata.AddDefaultExtensionProvider(() =>new AverageExtension());

base.CacheMetadata(metadata);
}

protectedoverridestring Execute(CodeActivityContext context)
{
// Get the average extension
var average = context.GetExtension<AverageExtension>();

if (average ==null)
thrownew InvalidOperationException("Cannot access AverageExtension");

var number = Number.Get(context);

// Store this number
average.StoreNumber(number);

returnstring.Format("Stored {0}, Average:{1}", number, average.GetAverage());
}
}

工作流服务如下:

如何测试:

1、添加WorkflowTestHelper引用

2、配置测试环境

3、为WorkflowService添加DeploymentItem属性标签。

4、使用WorkflowServiceTestHost宿主测试程序,代码如下:

代码

privatereadonly Binding _binding =new NetNamedPipeBinding();

///<summary>
/// The endpoint address to be used by the test host
///</summary>
privatereadonly EndpointAddress _serviceAddress =new EndpointAddress("net.pipe://localhost/TestService");

///<summary>
/// Tests the GetAverage Activity by invoking it in a WorkflowService multiple times
///</summary>
[TestMethod()]
[DeploymentItem("Service1.xamlx")]
publicvoid ShouldInvokeAverageExtension()
{
conststring expected1 ="Stored 33, Average:33";
conststring expected2 ="Stored 44, Average:38.5";
conststring expected3 ="Stored 55, Average:44";

string result1;
string result2;
string result3;

// Self-Host Service1.xamlx using Named Pipes
using (var testHost = WorkflowServiceTestHost.Open("Service1.xamlx", _serviceAddress.Uri))
{
// Use the generated proxy with named pipes
var proxy =new ServiceClient(_binding, _serviceAddress);

try
{
result1 = proxy.GetData(33);
result2 = proxy.GetData(44);
result3 = proxy.GetData(55);
proxy.Close();
}
catch (Exception)
{
proxy.Abort();
throw;
}

Assert.AreEqual(expected1, result1);
Assert.AreEqual(expected2, result2);
Assert.AreEqual(expected3, result3);
}
}

 总结:这篇文章是对WF4.0单元测试的一个简单介绍。WorklowTestHelper是一个MS的老外为WF4.0单元测试写的一个类库。测试类库和测试的例子http://code.msdn.microsoft.com/wfth/中都有下载。

 参考:http://blogs.msdn.com/b/rjacobs/archive/2010/09/13/how-to-unit-test-a-workflowservice.aspx

(全文完)


以下为广告部分

您部署的HTTPS网站安全吗?

如果您想看下您的网站HTTPS部署的是否安全,花1分钟时间来 myssl.com 检测以下吧。让您的HTTPS网站变得更安全!

SSL检测评估

快速了解HTTPS网站安全情况。

安全评级(A+、A、A-...)、行业合规检测、证书信息查看、证书链信息以及补完、服务器套件信息、证书兼容性检测等。

SSL证书工具

安装部署SSL证书变得更方便。

SSL证书内容查看、SSL证书格式转换、CSR在线生成、SSL私钥加解密、CAA检测等。

SSL漏洞检测

让服务器远离SSL证书漏洞侵扰

TLS ROBOT漏洞检测、心血漏洞检测、FREAK Attack漏洞检测、SSL Poodle漏洞检测、CCS注入漏洞检测。

WF4.0进行单元测试相关推荐

  1. WF4.0实战(六):控制WPF动画

    这个例子改造了王晓冬老师的:用WF流程控制WPF动画. 本文用一个小例子演示了在WF中定义两个操作步骤,用来控制WPF页面元素的动画.王冬老师当时使用的是WF3.0,现在我改成WF4.0. 先看效果: ...

  2. WF4.0实战(七):请假流程(带驳回操作)

    我使用WF4.0有很长一段时间了,但是对WF3.0和WF3.5自知甚少,对状态机也不甚了解.今天生鱼片前辈的博文:WF4实现工作流驳回流转模型的几种设计方案 中提出的四中实现驳回的方式中.第一种大家都 ...

  3. WF4.0实战(四):博客申请流程

    概述: 我是两年前申请的博客园.如今仍然记得很清楚,与现在的方式有点不同,当时注册也是要申请的,现在是注册不需要申请,而注册之后,开博需要申请.当时感觉有点新鲜,同样也感到欣慰,有如此敬业的管理员已经 ...

  4. WF4.0 基础篇 (十八) Flowchar

    本节主要介绍WF4 中 Flowchart的使用 本文例子下载: http://files.cnblogs.com/foundation/FlowcharSample.rar 本文例子说明 Flowc ...

  5. WF4.0 基础篇 (三) 流程实例WorkflowApplication与设计WF程序的基本原则

    通过本节,可以初步了解WF程序的特性,为以后的WF类应用开发提供一个初步的感性认识 目录 1    流程实例WorkflowApplication与设计WF程序的基本原则    1 1.1    流程 ...

  6. WorkFlow设计篇Step.2—传参的用法-订单金额的处理(续)-WF4.0

    开篇 上一篇,我们开始讲述WF4.0中的设计篇的开始,本系列主要讲述如何结合业务来设计工作流处理流程,并说明如何使用工作流流程来设计完成具体的业务流程处 理过程,将原来的代码处理业务流程,修改成WF可 ...

  7. [WF4.0]工作流设计器Rehosting(一)

    因为WF4.0使用WPF做可视化设计,能够利用WPF的数据绑定和其他一些内部实现,极大的简化了工作流设计器的开发工作:不用像3.5和3.0中那样,要开发一些服务类来支持工作流的设计操作. 首先看看Wo ...

  8. WF4.0入门系列1——创建一个简单的工作流

    WF4.0入门系列1--创建一个简单的工作流 打开VS2010,选择文件-新建-项目,选择Workflow项 工作流台应用程序,在名称处输入chapter01,选择合适的位置,这里默认,单击确定. V ...

  9. [转]WF4.0 基础篇 (一)开始使用WF

    本文转自:http://www.cnblogs.com/foundation/archive/2009/10/26/1589993.html 来博客园写WF主题博客已经3年了, 在园子里认识了很多朋友 ...

最新文章

  1. 自拟计算机作文100字,玩电脑作文100字胡佳慧
  2. GCC选项_-Wl,-soname
  3. STN32F103系列IO脚引脚分布
  4. Legal or Not
  5. Frame buffer分析 - fbmem.c【转】
  6. validate.js的使用
  7. 对计算机病毒防治最科学的方法是,计算机病毒防治(复习-3
  8. java stack长度_Java Stack size()用法及代码示例
  9. 赞美之外,Unity引擎3D引擎存在什么弊病?
  10. 押宝无线充电 苹果首款 “无线充电宝”曝光
  11. 一次新公司注册与小程序上线的历程
  12. url地址中有特殊符号“引号”引发的错误
  13. 【洛谷】P1067 多项式输出【模拟】
  14. 【UML 建模】在线UML建模工具 ProcessOn 使用具体解释
  15. ❤️数据可视化❤️:基于Echarts + GeoJson实现的地图视觉映射散点(气泡)组件【4】 - 广东省
  16. 图书推荐:《Web前端黑客技术揭秘》
  17. 为什么选独立服务器?
  18. [解读REST] 1.REST的起源
  19. mysql - user/privileges/用户与权限/用户权限/管理用户权限
  20. ios - 打开appstore应用、打开appstore评论、打开其他应用

热门文章

  1. 《AOSuite 开发手册》之AOSuite 服务端开发
  2. Android SDK上手指南:虚拟与物理设备
  3. EEPlat vs saleforce 配置 Knowledge Article 演示样例
  4. iOS学习笔记2-微博cell界面的实现
  5. Android ANR异常及解决方法
  6. 将表里的数据批量生成INSERT语句的存储过程 继续增强版
  7. 从Varchar转换为 datetime
  8. 演讲十忌(翻译并制作成PPT)
  9. ASP.NET十七种正则表达试
  10. JetBrains 2018 中国开发者生态报告:Java 最流行