5. おさらい:開発環境について
Express ではそのままだと無理
デザインコンポーネント拡張が必要な為
エディタを自前で用意すれば可能
WF 3.5
Visual Studio 2005
+ ExtensionS for Windows WF
Visual Studio 2008 Standard 以降
WF 4
Visual Studio 2010 Professional 以降
25. テストの作成
Imports Nunit.Framework
Public Class UnitTest1
<Test()>
Public Sub TestMethod1()
End Sub
End Class
NUnit
Imports Microsoft.VisualStudio.TestTools.UnitTesting
<TestClass()>
Public Class UnitTest1
<TestMethod()>
Public Sub TestMethod1()
End Sub
End Class MSTest
27. テストの作成
まずは要件を満たすテストを作成する
その際ビルドを通すために、アクティビティの
定義は同時に作成する
Imports System.Activities
Public Class ActivityT
Inherits CodeActivity
Public Property InParam1 As InArgument(Of String)
Public Property OutParam1 As OutArgument(Of Integer)Integer)
Protected Overrides Sub Execute(context As CodeActivityContext)
End Sub
End Class
29. テスト用ロジックの記載
<Test()>
Public Sub TestMethod1()
Const ORIGINAL_WORD = "Sample Word" 想定される結果
Const RESULTVALUE = 11
'テストするアクティビティの生成
Dim testActivity As New TDDSampleLib.ActivityT
'実行用 WorkflowInvoker の生成
Dim testInvoker As WorkflowInvokerTest = Nothing
Try
'アクティビティへパラメータを設定
Dim inArgs As New Dictionary(Of String, String)
inArgs.Add("InParam1", ORIGINAL_WORD)
'実行用 WorkflowInvoker の生成
testInvoker = New WorkflowInvokerTest(testActivity)
'実行
testInvoker.TestActivity(inArgs)
ワークフローの実行
'結果の確認
testInvoker.AssertOutArgument.AreEqual("OutParam1", RESULTVALUE)
Finally
testInvoker.Tracking.Trace()
End Try
End Sub
31. コーディング
テストを通過できるようアクティビティの
コーディングを行う
Imports System.Activities
Public Class ActivityT
Inherits CodeActivity
Public Property InParam1 As InArgument(Of String)
Public Property OutParam1 As OutArgument(Of Integer)
Protected Overrides Sub Execute(context As CodeActivityContext)
Dim inString = context.GetValue(Me.InParam1)
context.SetValue(Me.OutParam1, inString.Length)
End Sub
End Class
規則上は「テストを通過するように単純に」処理を書くよう言われるが
あまり正直にやりすぎるのも微妙なところ・・・
33. リファクタリング
サロゲートペア文字での
<TestCase("Sample Word", 11)> テストを追加
<TestCase("𠮟 る", 2)>
Public Sub TestMethod2(ByVal orgWord As String, ByVal result As Integer)
テストケースの追加
'テストするアクティビティの生成
Dim testActivity As New TDDSampleLib.ActivityT
'実行用 WorkflowInvoker の生成
Dim testInvoker As WorkflowInvokerTest = Nothing
Try
'アクティビティへプロパティを設定
testActivity.InParam1 = orgWord
'実行用 WorkflowInvoker の生成
testInvoker = New WorkflowInvokerTest(testActivity)
'実行
testInvoker.TestActivity()
'結果の確認
testInvoker.AssertOutArgument.AreEqual("OutParam1", result)
Finally
testInvoker.Tracking.Trace()
End Try
テストは失敗するので
End Sub
コードを修正する
34. <TestMethod()> MSTestの場合はTestCase属性
Public Sub TestMethod1()
TestInPrivate("Sample String", 13) (ROWテスト)が利用できない
TestInPrivate("𠮟 る", 2)
End Sub
Private Sub TestInPrivate(ByVal orgWord As String, ByVal result As Integer)
'テストするアクティビティの生成
Dim testActivity As New TDDSampleLib.ActivityT
'実行用 WorkflowInvoker の生成
Dim testInvoker As WorkflowInvokerTest = Nothing
Try
'アクティビティへプロパティを設定
testActivity.InParam1 = orgWord
'実行用 WorkflowInvoker の生成
testInvoker = New WorkflowInvokerTest(testActivity)
'実行
testInvoker.TestActivity()
'結果の確認
testInvoker.AssertOutArgument.AreEqual("OutParam1", result)
Finally
testInvoker.Tracking.Trace()
End Try
End Sub
独自に同様の属性を作成するか、親子関係の
テストメソッドとして作成するかで対応
MSDN Blog:Visual Studio Team Test
(http://blogs.msdn.com/b/vstsqualitytools/)
にて独自に属性を拡張する対応案について記載あり
(http://blogs.msdn.com/b/vstsqualitytools/archive/2009/09/04/extending-the-visual-studio-unit-test-type-
part-2.aspx)
35. Imports System.Activities
Public Class ActivityT
Inherits System.Activities.CodeActivity
Public Property InParam1 As InArgument(Of String)
Public Property OutParam1 As OutArgument(Of Integer)
Protected Overrides Sub Execute(context As CodeActivityContext)
Dim inString = context.GetValue(Me.InParam1)
Dim inStrInfo = New Globalization.StringInfo(inString)
context.SetValue(Me.OutParam1, inStrInfo.LengthInTextElements)
End Sub
End Class
リファクタリング後
再度テストを行いテストに
通過するのを確認
36. ブックマークのテスト
<Test()> WorkflowApplicationTest を
Public Sub TestBookmarkWorkflow() 利用したテストのサンプル
Const BOOKMARKNAME = "TestBookmark1"
Const SENDVALUE = "1"
'テストするアクティビティの生成
Dim testActivity As New ActivitySample
'実行用 WorkflowInvoker の生成
Dim testAppliaction As WorkflowApplicationTest(Of ActivitySample) = Nothing
Try
'実行用 WorkflowApplication の生成
testAppliaction = WorkflowApplicationTest.Create(testActivity)
'実行
testAppliaction.TestActivity()
'ブックマークの確認
Assert.IsTrue(testAppliaction.Bookmarks.Contains(BOOKMARKNAME))
Assert.AreEqual(BookmarkResumptionResult.Success,
testAppliaction.TestWorkflowApplication.ResumeBookmark(BOOKMARKNAME, SENDVALUE))
'終了まで待機
Assert.IsTrue(testAppliaction.WaitForCompletedEvent)
Finally
testAppliaction.Tracking.Trace()
ブックマークの状態確認と
End Try ブックマークの呼出確認が
End Sub
主なテスト内容となる
41. Visual Studio 上では xaml ファイルでのワー
クフローもクラスとして認識する
Express では
クラスとして認識しない
42. XamlInjector での呼出
<TestMethod()>
Public Sub TestMethodFromXaml()
Const ORIGINAL_WORD = "Sample Word"
Const RESULTVALUE = 11
XamlInjector にて動的に
ワークフローを呼び出し
Dim xl As New XamlInjector("Activity1.xaml")
Dim testActivity = xl.GetActivity アクティビティを取得
Dim testInvoker As WorkflowInvokerTest = Nothing
Try Activity クラスとして
'ワークフローへプロパティを設定
Dim inArgs As New Dictionary(Of String, Object) 取得できるので中身を
inArgs.Add("InParam1", ORIGINAL_WORD) 気にしなくてよい
'実行用 WorkflowInvoker の生成
testInvoker = New WorkflowInvokerTest(testActivity)
'実行
Dim result = testInvoker.TestActivity(inArgs)
'結果の確認
Assert.IsTrue(result.ContainsKey("OutParam1"))
Assert.AreEqual(RESULTVALUE.ToString, result("OutParam1").ToString)
Finally
testInvoker.Tracking.Trace()
End Try
End Sub
43. XamlInjector での呼出
<TestMethod()>
Public Sub TestMethodFromXaml()
Const ORIGINAL_WORD = "Sample Word" アクティビティのプロパティ
Const RESULTVALUE = 11
設定と異なり引数での受渡しは
Dim xl As New XamlInjector("Activity1.xaml")
Dim testActivity = xl.GetActivity
Dictionary を利用する
Dim testInvoker As WorkflowInvokerTest = Nothing
Try 引数は大文字小文字を
'ワークフローへプロパティを設定
Dim inArgs As New Dictionary(Of String, Object) 判別するので注意
inArgs.Add("InParam1", ORIGINAL_WORD)
'実行用 WorkflowInvoker の生成
testInvoker = New WorkflowInvokerTest(testActivity)
'実行
Dim result = testInvoker.TestActivity(inArgs)
'結果の確認
Assert.IsTrue(result.ContainsKey("OutParam1"))
Assert.AreEqual(RESULTVALUE.ToString, result("OutParam1").ToString)
Finally
testInvoker.Tracking.Trace()
End Try
End Sub
46. <"Sample Word", 11)> モックを利用したテストのサンプル
<TestCase("𠮟 る", 2)>
Public Sub TestServiceUseMock(ByVal orgWord As String, ByVal result As Integer)
Dim xl As New XamlInjector("TestService.xamlx")
'送受信アクティビティの置換
xl.ReplaceAll(GetType(Receive), GetType(ReceiveStub))
xl.ReplaceAll(GetType(Send), GetType(SendStub))
'ダミーのメッセージを設定
Dim stubExtension As New MessagingStubExtension OperationName と
stubExtension.EnqueueReceive( ServiceContracetName
XName.Get("{http://tempuri.org/}IService"),
"LengthCount", orgWord) の設定から記載
Dim svHost = WorkflowInvokerTest.Create(xl.GetWorkflowService.Body)
svHost.Extensions.Add(stubExtension)
Try
svHost.TestActivity()
Assert.AreEqual(2, stubExtension.Messages.Count)
Assert.AreEqual(result,
stubExtension.Messages(1).Content)
Finally
svHost.Tracking.Trace()
End Try
End Sub
47. <"Sample Word", 11)> モックを利用したテストのサンプル
<TestCase("𠮟 る", 2)>
Public Sub TestServiceUseMock(ByVal orgWord As String, ByVal result As Integer)
Dim xl As New XamlInjector("TestService.xamlx")
'送受信アクティビティの置換
xl.ReplaceAll(GetType(Receive), GetType(ReceiveStub))
xl.ReplaceAll(GetType(Send), GetType(SendStub))
'ダミーのメッセージを設定 WorkflowInvokerTest で
Dim stubExtension As New MessagingStubExtension
stubExtension.EnqueueReceive(
通常通りにテストを行う
XName.Get("{http://tempuri.org/}IService"),
"LengthCount", orgWord)
Dim svHost = WorkflowInvokerTest.Create(xl.GetWorkflowService.Body)
svHost.Extensions.Add(stubExtension)
Try
svHost.TestActivity()
Assert.AreEqual(2, stubExtension.Messages.Count)
Assert.AreEqual(result,
stubExtension.Messages(1).Content)
Finally
svHost.Tracking.Trace()
End Try
End Sub