Exercise 5: Testing Workflows
Up to this point, the application is not very interesting. It is only working in a console and does not receive any input arguments. Most applications that do meaningful work will have to deal with input and output arguments. Additionally, the application is not easily tested in its current form.
In this task, you will modify the SayHello activity to use arguments and prepare it to be useful in other non-console application environments by returning a greeting rather than writing directly to the Console with the WriteLine activity. You will be doing this using the "write the test first" approach. First, you will create a test that fails and then add the necessary code to make it pass.
The resulting application will be the equivalent of the following code.
private static string SayHello(string name) { return "Hello " + name + " from Workflow 4"; }
Private Shared Function SayHello(ByVal name As String) As String Return "Hello " & name & " from Workflow 4" End Function
Task 0 – Opening the Solution
To begin this exercise you can use the solution you finished from Exercise 4. Alternatively, you can follow the following steps to begin with Exercise 5.
- Start Microsoft Visual Studio 2010 from Start | All Programs | Microsoft Visual Studio 2010.
- Open the starting solution for Exercise 5 located under the Source\Ex5-Testing\Begin folder and use it as the starting point for this exercise.
- Press CTRL+SHIFT+B to build the solution.
Task 1 – Creating the Unit Test Project
To begin with, create a unit test for the workflow to verify the behavior. In Solution Explorer, right-click the HelloWorkflow solution and select Add / New Project and set the project options.
- Installed Templates: select either Visual C# or Visual Basic then select Test under the language
- Template: Test Project
- Name: HelloWorkflow.Tests
Figure 19
Adding a new Test Project to the solution (C#)
Figure 20
Adding a new Test Project to the solution (Visual Basic)
The default target version of the .NET Framework in test projects is the .NET Framework 4. However, Visual Studio 2010 SP1 Beta adds basic support for unit tests that target the .NET Framework 3.5. For more information, see
https://msdn.microsoft.com/library/gg442059.aspx
- Right-click the HelloWorkflow.Tests project and click Add Reference. Using the Projects tab, add a project reference to the HelloWorkflow project. Repeat these steps, using the .NET tab instead to add a reference to the System.Activities library.
- Right-click UnitTest1.cs (C#) or UnitTest1.vb (Visual Basic), click Rename and change its name to SayHelloFixture.cs (C#) or SayHelloFixture.vb (Visual Basic). When prompted to rename the UnitTest1 class select Yes.
Task 2 – Creating the Test
In this task you will create the test before you actually implement the behavior in the activity.
Add the following namespace directive to the SayHelloFixture.cs (C#) file or SayHelloFixture.vb (Visual Basic):
using System.Activities; using HelloWorkflow;
Imports System.Activities Imports HelloWorkflow
- Create a test to make sure that the workflow properly greets you. To do this, open SayHelloFixture.cs (C#) or SayHelloFixture.vb (Visual Basic), locate the TestMethod1 method and rename it to ShouldReturnGreetingWithName.
The SayHello activity does not accept any arguments yet, but you will write the code to invoke it as though it does. This will allow you to think about what the interface to your activity feels like when consuming it. Do not worry if Visual Studio warns you about the UserName property not being defined yet. Replace the implementation as shown
(Code Snippet - Introduction to WF4Lab - ShouldReturnGreetingImpl CSharp)
[TestMethod] public void ShouldReturnGreetingWithName() { IDictionary<string, object> output; output = WorkflowInvoker.Invoke( new SayHello() { UserName = "Test" }); Assert.AreEqual("Hello Test from Workflow 4", output["Greeting"]); }
(Code Snippet - Introduction to WF4Lab - ShouldReturnGreetingImpl VB)
<TestMethod()> Public Sub ShouldReturnGreetingWithName() Dim output = WorkflowInvoker.Invoke( New SayHello() With {.UserName = "Test"}) Assert.AreEqual("Hello Test from Workflow 4", output("Greeting")) End Sub
How do I pass arguments to an activity?
You can create the activity and initialize the arguments (which are public properties) using object initialization or you can pass a Dictionary<string, object> (C#) or Dictionary(Of String, Object) (Visual Basic) of input parameters that map to the names of the input arguments of the activity.
How do I get data from output?
The output variable is an IDictionary<string, object> (C#) or IDictionary(Of String, Object) (Visual Basic) that contains a map of output variables using the name of the variable as the key.
Task 3 – Getting the Application to Compile
The interface to your Activity (in terms of input and output arguments) looks good but your application doesn’t compile. Your first goal is to get the app into a state where it will compile.
Press CTRL+SHIFT+B to build the application it should fail with a compile error
Figure 21
UserName has not been defined yet (C#)
Figure 22
UserName has not been defined yet (VB)
- Open SayHello.xaml in the designer
Open the arguments pane by clicking on Arguments
Figure 23
Click on Arguments to open the arguments pane
Add the UserName and Greeting arguments as shown
Figure 24
Declare the arguments to the activity
Arguments
In Windows Workflow Foundation (WF), arguments represent the flow of data into and out of an activity
. An activity has a set of arguments and they make up the signature of the activity. Each argument has a specified direction: input, output, or input/output.
- Press CTRL+SHIFT+B to build the solution, it should now build without errors.
Task 4 – Seeing the Test Fail
It is important to see your test fail because it is possible that you have a bug in your test that would cause it to always succeed. In this task, you will insure that your test does indeed fail.
Press CTRL+R,T to run the unit tests in the current context. The test will run but it will fail, because the activity is not returning anything in the Greeting out argument.
Figure 25
ShouldReturnGreetingwithName test
Task 5 – Making the Test Pass
Now that you know your test is working, you need to do the simplest possible thing you can to make the test pass.
- Writing text to the console with WriteLine isn’t going to make the test pass so delete the WriteLine activity by right-clicking on it and choosing Delete ().
You need to set the value of the Greeting out argument. To do this, drag an Assign activity from the Primitives group in the Toolbox and drop it onto the designer surface.
Figure 26
Drag an Assign activity to the design surface
Set the To property to Greeting
Figure 27
Type Greeting in the left box
You could type the greeting expression into the design surface but since the expression is longer, use the properties window. Click the button to the right of the Value property to open the expression editor
Figure 28
Click the button to the right of the Value property
In the expression editor, you can enter longer expressions, including expressions that use the VB line continuation character “_”. Set the expression to "Hello " & UserName _& " from Workflow 4"
Figure 29
The Assign activity that sets the Greeting argument
If you are a C# developer you may not be familiar with the line oriented nature of Visual Basic syntax. If you want an expression to break across lines in Visual Basic you must use an underscore to continue the expression on the next line.
- Press CTRL+SHIFT+B to build the solution, it should compile without errors.
Next Step
Exercise 5: Verification