Click here to Skip to main content
Click here to Skip to main content

BizUnit 4.0 and BizTalk 2010 - Simple Orchestration

, 18 Feb 2014
Rate this:
Please Sign up or sign in to vote.
This article will demonstrate how to use BizUnit 4.0 to unit test a simple orchestration in BizTalk 2010.

Introduction

In May 2011, a new version of BizUnit was released. This article hopes to demonstrate how to use BizUnit 4.0 to unit test a simple orchestration in BizTalk 2010. This will be the first of a number of BizUnit and BizTalk 2010 related articles.

This article covers a very simple scenario that demonstrates a small part of the abilities of BizUnit. Unit testing an orchestration.

Background

Unit testing is invaluable in software development and it is something that is tricky to do with BizTalk but at the same time it is essential that it happens. BizUnit is a brilliant tool and should be used routinely by BizTalk developers to ensure the quality of the code that they are producing.

BizUnit takes a black box approach to testing BizTalk applications. The test in this article does the following:

  1. Copies a sample file and drops it into a BizTalk receive location
  2. Checks that the correct number of files arrive in the destination location
  3. Validates those files against the XSD
  4. Check the content of the file

Required Download

The latest version of BizUnit (Version 4 for this article) should be downloaded from CodePlex.

Required Software

The following software is required to run the sample code:

  • Visual Studio 2010
  • Microsoft BizTalk Server 2010

Sample BizTalk Project

Before we can do any testing, we need to create a test project. To do that, we need to define three schemas, two maps and an orchestration. This is a very very simple project but should be enough to get going.

Now, as everyone knows, in the TDD world we would write the tests before the code and then make the tests pass. This cannot really be done in BizTalk in the purest form. You will need the input and output schemas at the very least.

Remember to Strong Name the BizTalk solution or you will be unable to deploy it.

Schemas

The schemas we are going to define are an input schema to represent a customer order and then two output schemas which are a very simple order summary and a pick list. They are simple schemas and not exactly realistic but they serve the purpose of the article.

Source Schema

The source schema represents a multiline customer order. A single order can have multiple lines, each with a quantity and a price. It is a simple schema but will serve the purposes of this article.

Source Schema

The sample file used for the tests is:

<ns0:CustomerOrder xmlns:ns0="http://Timewave.BizTalkUnit.Sample.SourceSchema">
  <Forename>Tycho</Forename>
  <Surname>Lien</Surname>
  <CustomerId>10000001</CustomerId>
  <OrderTotal>1000.00</OrderTotal>
  <PaymentStatus>Paid</PaymentStatus>
  <OrderLines>
    <Line>
      <ItemId>1234</ItemId>
      <ItemQty>1</ItemQty>
      <PriceAtOrder>399.99</PriceAtOrder>
    </Line>
    <Line>
      <ItemId>2345</ItemId>
      <ItemQty>1</ItemQty>
      <PriceAtOrder>100.01</PriceAtOrder>
    </Line>
    <Line>
      <ItemId>3456</ItemId>
      <ItemQty>1</ItemQty>
      <PriceAtOrder>500.00</PriceAtOrder>
    </Line>
  </OrderLines>
</ns0:CustomerOrder>

Pick List Schema

The pick list schema will be a list of the items contained in the customer order (source schema). It isn't used as part of the test in this article.

Pick List Schema

Summary Schema

The summary schema will contain the details of the customer and a count of the number of items ordered.

Summary Schema

Maps

We are going to create two maps. These maps will transform the source message into the Summary Message and the PickList Message.

Summary Map

The summary map takes the values from the customer order (source schema) and transforms them to the summary schema. Not all of the values from the source schema are used. The Forename and Surname elements are concatenated using a string concatenate functoid. A Record Count functoid is used to get a count of the number of items.

Summary Map

Pick List Map

The pick list map simply transforms the customer order (source schema) document to the pick list schema. The CustomerId used and a looping functoid makes sure that an Item is created for each order line.

Pick List Map

Orchestration

The orchestration is, once again, relatively simple. A document that conforms to the source schema is picked up from a file location and pulled into the orchestration. The file is transformed to the summary schema and then a send port places it into the relevant file location. The same source document is then transformed to the pick list schema and then placed into the pick list file location.

ProcessOrder.odx

Orchestration

Simple, but all we need for the purposes of this test.

BizTalk Deployment

I have assumed that you know how to build a BizTalk solution and deploy it to BizTalk and as such I am not going to cover that here.

Just make sure that the receive and send locations in BizTalk match those on the test project that follows.

Test Project

Once the BizTalk project is up and running and deployed to BizTalk, then it is time to create the test project. In the real world, you should have done this just after having created the BizTalk project. The tests would be being created after having built the Schemas and before doing anything else.

So, add a test project to the solution.

Add Test Project

Next, we need to add the BizUnit references to the test project. You will need to browse to these, they will be at C:\Program Files\BizUnit\BizUnit 4.0\Bins, assuming a standard installation.

Add BizUnit References

You need to add references to:

  • BizUnit
  • BizUnit.TestSteps
  • BizUnit.TestSteps.BizTalk

Once that is done, we are ready to start creating our test method. Now, I am using resharper which nicely adds "using" statements for me. Assuming that you are not, then make sure you have using statements for the references that we added previously.

The code that follows is the complete code for the test method. I will break down each part of the code and explain it afterwards. One important point to note is that none of the code takes any action until the final RunTest() command. One of the features of BizUnit is that tests can be scripted in XAML (XML in previous versions). The next article will show this same example using the XAML script.

[TestMethod]
public void Total_Items_Is_3()
{
var totalItemsTest = new TestCase { Name = "Total Items is 3" };

//Get rid of any files that are already there
DeleteStep deleteStep = new DeleteStep();

var filePathsToDelete = new Collection<string> {@"..\..\..\Pickup\Out\Summary\*.xml"};

deleteStep.FilePathsToDelete = filePathsToDelete;
totalItemsTest.SetupSteps.Add(deleteStep);

//We don't do this as it won't be in the XAML
//deleteStep.Execute(new Context());

//Create the test step
var testStep = new CreateStep();
//Where are we going to create the file
testStep.CreationPath = @"..\..\..\Pickup\In\InboundCorrect.xml";
var dataLoader = new FileDataLoader();
//Where are we getting the file from?
dataLoader.FilePath = @"..\..\..\TestData\InboundCorrect.xml";
testStep.DataSource = dataLoader;

totalItemsTest.ExecutionSteps.Add(testStep);

//Create a validating read step
//We should only have one file in the directory
var validatingFileReadStep = new FileReadMultipleStep
{
DirectoryPath = @"..\..\..\Pickup\Out\Summary",
SearchPattern = "*.xml",
ExpectedNumberOfFiles = 1,
Timeout = 3000,
DeleteFiles = true
};

//Create an XML Validation step
//This will check the result against the XSD for the document
var validation = new XmlValidationStep();
var schemaSummary = new SchemaDefinition
{
XmlSchemaPath =
@"..\..\..\Timewave.BizUnit.Sample\Schemas\SummarySchema.xsd",
XmlSchemaNameSpace =
"http://Timewave.BizTalkUnit.Sample.DestinationSchema"
};
validation.XmlSchemas.Add(schemaSummary);

//Create an XPath Validation. This will check a value in the output.
//The Xpath for the node can be grabbed from the Instance XPath property on the XSD.
var xpathProductId = new XPathDefinition
{
Description = "ItemsOrdered",
XPath =
"/*[local-name()='CustomerSummary' and
namespace-uri()='http://Timewave.BizTalkUnit.Sample.DestinationSchema']/
*[local-name()='ItemsOrdered' and namespace-uri()='']",
Value = "3"
};
validation.XPathValidations.Add(xpathProductId);

validatingFileReadStep.SubSteps.Add(validation);

totalItemsTest.ExecutionSteps.Add(validatingFileReadStep);

var bizUnit = new BizUnit.BizUnit(totalItemsTest);
bizUnit.RunTest();
}

The first part of the code might prove controversial. Personally, I think it is a style thing rather than a big issue. The first thing I do in each of my tests is make sure that the location I am going to be checking for the result is empty. Some articles on BizUnit suggest that this should be the last step, leave the system how it started, which I agree with, but I like to assume the worst, that a previous test has left a file in place which will give me a false positive, so I empty the location at the start. It is up to you if you do it at the start, end or both!

[TestMethod]
public void Total_Items_Is_3()
{
var totalItemsTest = new TestCase { Name = "Total Items is 3" };

//Get rid of any files that are already there
DeleteStep deleteStep = new DeleteStep();

var filePathsToDelete = new Collection<string> {@"..\..\..\Pickup\Out\Summary\*.xml"};

deleteStep.FilePathsToDelete = filePathsToDelete;
totalItemsTest.SetupSteps.Add(deleteStep);

//We don't do this as it won't be in the XAML
//deleteStep.Execute(new Context());

This is all reasonably straight forward, one thing to note. You cannot do:

deleteStep.FilePathsToDelete.Add(filename);

The reason being the BizUnit 4.0 (currently) does not initialise the collection in the class constructor so it causes an "Object reference not set" error.

totalItemsTest.SetupSteps.Add(deleteStep) will add the deletion step to the steps that will take place when the test is executed.

It is possible to replace totalItemsTest.SetupSteps.Add(deleteStep) with deleteStep.Execute(new Context()). This will cause the deletion step to happen immediately. However, if the test is serialised to XAML, then the step will not be included.

The next task is to create the test step itself.

 //Create the test step
var testStep = new CreateStep();
//Where are we going to create the file
testStep.CreationPath = @"..\..\..\Pickup\In\InboundCorrect.xml";
var dataLoader = new FileDataLoader();
//Where are we getting the file from?
dataLoader.FilePath = @"..\..\..\TestData\InboundCorrect.xml";
testStep.DataSource = dataLoader;

totalItemsTest.ExecutionSteps.Add(testStep);

The CreationPath is the path (directory and filename) that BizTalk should be watching with a receive port. This is where the file will arrive to be picked up by BizTalk. It is NOT the path that BizTalk will create the response.

The FilePath is where BizUnit will go and get the sample from. In a real solution, this directory will contain all of your test documents.

Next, we create the steps that will take place after the test has fired. We are going to carry out 3 different checks. We are going to:

  1. Check that a single document has been produced
  2. Check that the document is valid against the XSD
  3. Check that a calculated value in the document is correct

To check that a file has been created, we create a FileReadMultipleStep. This will go and check a particular directory for files that meets a certain pattern. I have used *.xml but it could easily be PO*.xml if your port uses a file name to distinguish output files.

//Create a validating read step
//We should only have one file in the directory
var validatingFileReadStep = new FileReadMultipleStep
{
DirectoryPath = @"..\..\..\Pickup\Out\Summary",
SearchPattern = "*.xml",
ExpectedNumberOfFiles = 1,
Timeout = 3000,
DeleteFiles = true
};

So, the values here are reasonably obvious, we have the directory to check, the pattern of the file we are looking for, the number of files expected and the timeout. We also have a flag that tells BizUnit if it should delete the file(s) when it is done.

The Timeout is important. If you have a complex orchestration that can take some time to run, then you will need to set this timeout. Your test has absolutely no knowledge of what is creating the file that it is looking for. It cannot check to see if BizTalk is done or if there is a delay on server or if a web service is spinning up. You need to use your judgement to set this to a realistic timeout. In my case, 3 seconds (3000 milliseconds) was sufficient.

DeleteFiles will make this step delete the file once it has finished with it. It is good to tidy up after yourself! Remove this if you want to see the file that is produced.

Next we check that the XML is valid.

//Create an XML Validation step
//This will check the result against the XSD for the document
var validation = new XmlValidationStep();
var schemaSummary = new SchemaDefinition
{
XmlSchemaPath =
@"..\..\..\Timewave.BizUnit.Sample\Schemas\SummarySchema.xsd",
XmlSchemaNameSpace =
"http://Timewave.BizTalkUnit.Sample.DestinationSchema"
};
validation.XmlSchemas.Add(schemaSummary);

Again, this is straight forward. Make sure that you get the XmlSchemaNameSpace correct as this will ensure a failure if it is wrong.

Next we create an XPath Validation. This will go and check that the output document has a value in it as expected.

//Create an XPath Validation. This will check a value in the output.
//The Xpath for the node can be grabbed from the Instance XPath property on the XSD.
var xpathProductId = new XPathDefinition
{
Description = "ItemsOrdered",
XPath =
"/*[local-name()='CustomerSummary' and namespace-uri()=
'http://Timewave.BizTalkUnit.Sample.DestinationSchema']/
*[local-name()='ItemsOrdered' and namespace-uri()='']",
Value = "3"
};
validation.XPathValidations.Add(xpathProductId);

The three parameters used to construct the XPathDefinition are a Description, the XPath for the element you are checking (which is copy and pasted from the XSD in the BizTalk XSD editor) and the value that you are expecting.

The final part of the code adds the validations we have just created to the test and then runs the test.

 validatingFileReadStep.SubSteps.Add(validation);

totalItemsTest.ExecutionSteps.Add(validatingFileReadStep);

var bizUnit = new BizUnit.BizUnit(totalItemsTest);
bizUnit.RunTest();

Using the Code

To run the tests, you will need to deploy your solution to BizTalk and configure the ports.

Test Results

Then, right click on the test and select run test. Once the test has run, you will either see "Passed" or "Failed". If it says failed, then right click on the result and select "View Test Results Details". You can then use the details to work out what the issue is. Please remember the points in the next section.

If Your Tests Fail

Unlike usual unit testing, a BizUnit test may fail for reasons other than the code being broken. Please remember the following when investigating failed tests. The test in the sample could fail for 3 different reasons. These are:

  • No file in the specified directory
  • Too many files in the specified directory (If this happens, then the delete is failing)
  • XPath match failure

Now, under normal circumstances, you would dive into the code to find the bug that has been introduced. Before you do that, double check the following:

  • The BizTalk application is running
  • Your receive adapters are enabled
  • Your send port is enabled
  • The Orchestration is enlisted
  • The Host instance is running
  • The timeout in the code is long enough if you have a complex process

Next Steps

The next article will show how to do the exact same test as documented here, but with the tests defined in XAML rather than code.

History

  • Initial version - 2011-08-20

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Neil Weller
Architect Timewave Technologies Ltd
United Kingdom United Kingdom
I graduated from Sussex University in 1994 after spending 3 years studying Computing and Artificial Intelligence for a BA(Hons).
 
My first job was with a consultancy company programming in VB3 with SQL Server 4.21. During my time with that consultancy Java was released and I spent my own time learning it. I left after 3 years to start in business on my own. I spent a while providing VB and Java consultancy. I then moved into C# when .Net was first released and started working with BizTalk in 2004.
 
In 1997 I founded Timewave Technologies Ltd, a small consultancy providing solutions to all sizes of organisations in all areas of development and integration.
 
I have a passion for BizTalk and all things Integration related. I also have a few apps on the WP7 marketplace.
Follow on   Twitter

Comments and Discussions

 
QuestionHow does DeleteFiles = True work? PinmemberMember 1094043611-Jul-14 5:37 
QuestionSimilar blog flat file Pinmemberparashu Kambale3-Feb-13 22:39 
QuestionSome more samples Pinmemberparashu Kambale23-Jan-13 17:58 
Questionworks smoothly Pinmemberparashu Kambale18-Dec-12 0:11 
GeneralMy vote of 5 Pinmemberaki12345678923-Feb-12 22:37 
QuestionUsing BizUnit 4 for validating Flafile outputs Pinmemberganeshpaduvary11-Nov-11 5:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 18 Feb 2014
Article Copyright 2011 by Neil Weller
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid