求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
 
WF4.0进行单元测试
 

2011-4-11 来源:网络

 

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

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

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

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

[TestMethod]
public void 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]
public void 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是用来暂停流程,等待响应的。下面是一个书签活动的代码:

public sealed class ReadLine : NativeActivity<string>
{
private BookmarkCallback _readCompleteCallback;

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

protected override bool CanInduceIdle
{
get { return true; }
}

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

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

private void OnReadComplete(NativeActivityContext context, Bookmark bookmark, object state)
{
// Store the value returned by the host
context.SetValue(Result, state as string);
}
}

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

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

如何测试这个流程。

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

[TestMethod]
public void ShouldOutputGreeting()
{
// Arrange
const string expectedFirstName = "Test";
const string 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 public class AverageExtension
2 {
3 private static readonly List<int> Numbers = new List<int>();
4
5 public static void Reset()
6 {
7 Numbers.Clear();
8 }
9
10 public void StoreNumber(int num)
11 {
12 Numbers.Add(num);
13 }
14
15 public double GetAverage()
16 {
17 return Numbers.Average();
18 }
19 }

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

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


protected override void 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);
}

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

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

var number = Number.Get(context);

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

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

工作流服务如下:

如何测试:

1、添加WorkflowTestHelper引用

2、配置测试环境

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

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

private readonly Binding _binding = new NetNamedPipeBinding();

/// <summary>
/// The endpoint address to be used by the test host
/// </summary>
private readonly 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")]
public void ShouldInvokeAverageExtension()
{
const string expected1 = "Stored 33, Average:33";
const string expected2 = "Stored 44, Average:38.5";
const string 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单元测试写的一个类库。 



LoadRunner性能测试基础
软件测试结果分析和质量报告
面向对象软件测试技术研究
设计测试用例的四条原则
功能测试中故障模型的建立
性能测试综述
更多...   


性能测试方法与技术
测试过程与团队管理
LoadRunner进行性能测试
WEB应用的软件测试
手机软件测试
白盒测试方法与技术


某博彩行业 数据库自动化测试
IT服务商 Web安全测试
IT服务商 自动化测试框架
海航股份 单元测试、重构
测试需求分析与测试用例分析
互联网web测试方法与实践
基于Selenium的Web自动化测试
更多...