Wednesday, March 14, 2007

Getting started with NUnit and BizUnit

When it comes to testing your BizTalk applications, NUnit and BizUnit are often used. Where NUnit is a unit-testing framework for .NET languages, BizUnit can be used for testing your BizTalk 2004/2006 solutions. This article describes which tools need to be installed and helps you to setup your first test project.

What is NUnit
As stated, NUnit is a unit-testing framework for .NET languages. The test cases you create with BizUnit are added to and executed from the NUnit user interface. The results from the test runs can be viewed in NUnit as well.

What is BizUnit

The test cases you need to test your BizTalk solutions are created with BizUnit. Although you need to create a Class library in Visual Studio to be able to have the test cases executed, most of the test case creation is done with XML files. With these XML files you can prepare your test environment, execute your tests and cleanup your test environment. You can setup tests for the following adapters: FILE, HTTP, SOAP, MSMQ, MQSeries and POP3. Further BizUnit allows you to perform multiple kinds of validation and load data in the context. It's also possible to query the EventLog.

What do you need to install
The two most recent BizTalk versions are supported by NUnit and BizUnit.

For testing BizTalk 2004 applications you need to install:

For testing BizTalk 2006 applications you need:
Install both tools keeping the defaults for the installation directories.

The sample orchestration
For this article I created an orchestration that will be tested. I have a simple scenario which contains the following steps:
  • receive a message on a file location
  • log to the EventLog that the message is received
  • send the message to another file location
  • log to the EventLog that the message is sent
The orchestration looks as follows:

Fig. 1 - The orchestration which will be tested

Setting up your test environment
During the setup of a test project a number of artifacts is created. Since it is convenient to have everything at one place, we need a folder structure, which will contain all these artifacts. For this sample this structure looks as follows:

fig2Fig. 2 – Folder structure of the test environment

The C:\NUnitBizUnit folder contains:
  • BizTalkia folder (Visual Studio solution which contains the sample BizTalk project and test project)
  • Receive folder (Receive file Location for the orchestration)
  • Send folder (Send file location for the orchestration)
  • TestCases (test case configuration files)
  • BizTalkia.dll (the Test project assembly which we will create in Visual Studio)
  • BizTalkia.nunit (NUnit project file for this sample)
  • Microsoft.Services.BizTalkApplicationFramework.BizUnit.dll (referenced from BizTalkia.dll)
  • nunit.core.dll (referenced from BizTalkia.dll)
  • ReceivedFileInstance.xml (used to kick off the orchestration)
At this moment you might not yet be familiar with all the artifacts mentioned above, but most of them will be explained in this article.

Create a Test project in Visual Studio
We need a C# Class library project, which will contain the Test project. It must have references to the following binaries:
  • C:\Program Files\NUnit-Net-2.0 2.2.9\bin\nunit.core.dll
  • C:\Program Files\NUnit-Net-2.0 2.2.9\bin\nunit.framework.dll
  • C:\Program Files\Microsoft Services\BizUnit 2.2\bins\ Microsoft.Services.BizTalkApplicationFramework.BizUnit.dll
  • C:\Program Files\Microsoft Services\BizUnit 2.2\bins\ Microsoft.Services.BizTalkApplicationFramework.BizUnit.MQSeriesSteps.dll (only in case you will have to test MQSeries) .

    Fig. 3 – Solution Explorer with newly added references and class

    The Class library has a class file which will hold the test code. The following code can be used as a template for the class file:

    using NUnit.Framework;
    using Microsoft.Services.BizTalkApplicationFramework.BizUnit;

    namespace <namespace>

    public class <class name>
    public void <method name>()
    BizUnit bizunit = new BizUnit(@"<location/name configuration file>");
Replace <namespace> by a namespace that suits you. I add my test projects to the same solution which contains my BizTalk project(s). So I derive the namespace for my test project from the namespaces I use for my BizTalk project.

Also replace <class name> with a convenient and descriptive name. Both the class names and method names will show up in NUnit.

The code in my sample project looks as follows:

namespace BizTalkia.Test
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using Microsoft.Services.BizTalkApplicationFramework.BizUnit;

public class BizUnitTestClass
public void Test_01_SubmitFile()
BizUnit bizunit = new BizUnit(@".\TestCases\BizTalkia.Test.SubmitFile.xml");
public void Test_02_CheckFileReceived()
BizUnit bizunit = new BizUnit(@".\TestCases\BizTalkia.Test.CheckFileReceived.xml");
public void Test_03_CheckSentFileExists()
BizUnit bizunit = new BizUnit(@".\TestCases\BizTalkia.Test.CheckSentFileExists.xml");

As you see there is one class with 3 methods. Each method defines a test case. These test cases are described below. You are free in creating more than one class, as long as each class is public and has the [TestFixture] attribute. Each method must be public as well and must have the attribute [Test]. The methods are numbered from 01 to 03. This is necessary, since otherwise in NUnit the methods will show up alphabetically, which will process your test cases in the wrong order. Further you see that each method refers to a test case configuration file of its own.

Build the test project
Now that we have described the class library the test project can be build.

Fig. 4 – Build the test project

The assembly needs to be copied to the C:\NUnitBizUnit folder, along with its references.

Test case configuration files
The test case configuration files (which are stored in C:\NUnitBizUnit\TestCases) define the test cases. Before going into detail, first let's have a look at the structure of the configuration files. We therefore use the first test case configuration file of this sample, namely BizTalkia.Test.SubmitFile.xml.

<TestCase testName="BizTalkia.Test">
<TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.FileDeleteMultipleStep"> <Directory>C:\NUnitBizUnit\Send</Directory>

<TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.FileCreateStep"> <SourcePath>C:\NUnitBizUnit\ReceivedFileInstance.xml</SourcePath> <CreationPath>C:\NUnitBizUnit\Receive\InFile.xml</CreationPath> </TestStep>
<!-- Test cleanup: test cases should always leave the system in the state they found it -->

This test case file has a TestSetup, TestExecution and a TestCleanup node. The goals of these nodes are obvious: the TestSetup node is used for setting/preparing up your test environment, the TestExecution node contains all your test steps and the TestCleanup node is used for cleaning up your test environment. The TestSetup and TestCleanup nodes are optional.
Each of the nodes can contain one or more test steps. Check the BizUnit documentation for the available test steps.

Submitting a file

Since SubmitFile is my first test case, inside the TestSetup node some cleanup of the test environment is done. In this case any existing files in a particular folder are deleted. Therefore the FileDeleteMultipleStep test step is used.

The sample orchestration is kicked off by submitting a file on a File Receive Location. In the TestExecution node I use the FileCreateStep test step to have a file created in a particular folder. The SourcePath node is used to determine which file is used as a template for the file that needs to be created. With the CreationPath node I determine where a copy of the file mentioned in the SourcePath node will be placed. So actually a file copy is done. The CreationPath node should contain the path to your Receive Location as it is configured in BizTalk.

Check if the file is received
Now that we have taken care of instantiating the orchestration, let's check if the orchestration really has received the file. The orchestration writes an EventLog entry to confirm that a file is received. Therefore in the next test case we query the EventLog to check if the orchestration did write that EventLog entry. The code in the Expression shape that writes to the EventLog looks as follows:

// Write to EventLog
System.Diagnostics.EventLog.WriteEntry("BizTalkia", "File received", System.Diagnostics.EventLogEntryType.Information, 1);

In test case file CheckFileReceived.xml we query the EventLog. Since this test case does not need setup or cleanup of the test environment, the nodes TestSetup and TestCleanup are left out. Quering of the EventLog is done with the EventLogCheckStep test step.

<TestCase testName="BizTalkia.Test">
<TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.EventLogCheckStep"> <DelayBeforeCheck>10</DelayBeforeCheck> <!-- Optional, seconds to delay performing check -->

The DelayBeforeCheck node is used to set the number of seconds to wait, before the EventLog is queried. This way you give BizTalk some time to retrieve the message and write to the EventLog. The FailIfFound node is used to determine if the test case should fail, in case that the EventLog entry is not found. The other nodes are used to query the EventLog. Although the test case does not query the actual message which is written to the EventLog ("File received"), also this can be queried with a regular expression validation.

Check if the file is sent
The orchestration now should send the message to another file location. With BizUnit we can check if a file exists in a certain folder. This test is done in test case file CheckSentFileExists.xml.

<TestCase testName="BizTalkia.Test">
<TestStep assemblyPath="" typeName="Microsoft.Services.BizTalkApplicationFramework.BizUnit.FilesExistStep"> <Timeout>3000</Timeout>

In this test case BizTalk is given some time (by means of the Timeout node) to send out the message, before the existance of the file is checked.
With the DirectoryPath node and the SearchPattern node we determine where and what we are looking for.

So far the description of the test cases and steps.

Creating a NUnit project
Most of the work is done by now. NUnit works with project files which contain references to the assemblies which contain the test project.
The image below shows the NUnit interface with the dialog to create a new project file.

Fig. 5 – Create a new NUnit project

The NUnit project is stored in C:\NUnitBizUnit. Test projects assemblies must be added to the project. This can be done by navigating in the menu to Project, Edit… In the dialog that appears select the Assemblies tab page, click Add Assembly… to add the assembly.

Fig. 6 – Add the assembly

Run the test
The test environment is now set up and ready to run the test! In the Tree view you see the structure of the assembly. By selecting (the class) BizUnitTestClass and clicking Run, all underlying tests are executed. The bullets can have the following colors:
  • gray: not yet executed
  • green: tested successfully
  • yellow: test not run
  • red: tested unsuccessfully
The test results can be viewed on the tab pages.

Fig. 7 - NUnit project before run

Fig. 8 – NUnit project after (successful) run

Both NUnit and BizUnit are still under development. So bugs become solved and functionality is added. In this article I wanted to give you a quick start with using NUnit and BizUnit.
Hopefully I succeeded in that goal. Please feel free to give any comments.

The solution can be downloaded here.


Anonymous said...

Thanks Guys, I've been trying to find time to start testing using BizUnit but never knew where to start!

This is a great introduction.

Cheers, Nick.

Lex Hegt said...

You're welcome Nick!
You're quick in finding it! I posted it half an hour ago!


Rodney J. Woodruff said...

Do you have the solution for this tutorial available for download? Thanks.

Lex Hegt said...


My VPC-image which contained the solution crashed, but I've recreated the solution and added a link to it to the article.
If you have any questions about it, please let me know!