BizTalk Server 2013: Step-by-Step to implement Unit Testing in Schemas and Maps
Introduction
Testing is an important aspect of (BizTalk) application life cycle. Before a developer deploys his solution he needs to be confident that it will perform, and do the task(s) it is intended to do. It is a developers responsibility that he creates a robust application. Therefore he needs to unit test his BizTalk application artifacts before he deploys them for further testing.
A BizTalk developer has a couple of options when it comes to unit testing BizTalk artifacts. Testing of each can be done using a framework like BizUnit, or some of the other available tools offered through CodePlex, or Visual Studio. With BizTalk Server 2009 the unit test feature was introduced, which offered built-in developer support for testing schemas, maps and pipelines in Visual Studio. The test capabilities offered by Visual Studio in for BizTalk artifacts are the following:
- Validating an XML document instance.
- Testing a map.
- Unit test a schema, map and/or a pipeline.
This article will explain step-by-step how we can implement unit test in BizTalk Server 2013 project within Visual Studio 2012 to test Schemas and Maps.
Step-by-Step Implementation
Adding a Unit Test Project to your BizTalk Solution
To implement unit test within Visual Studio 2012 to test Schemas and Map we need to:
- Open your BizTalk Project in Visual Studio.NET 2012, in this sample: "UnitTestingFeatureWithMaps.sln"
- In Solution Explorer, right-click in the BizTalk Server project, in this sample "UnitTestingFeatureWithMaps", and then click Properties.
- In Project Designer, click the Deployment property page tab and set "Enable Unit Testing" option to "True".
-
- Close the project properties page saving the changes.
This feature allows you to create unit tests for schemas, maps, and pipelines. The topics in this section provide some example approaches to using the unit testing feature. When this feature is enabled and the project rebuilt, the artifact classes will be derived from the following base classes to support unit testing.
Artifact type | Base class |
Schema |
Microsoft.BizTalk.TestTools.Schema.TestableSchemaBase |
Map |
Microsoft.BizTalk.TestTools.Mapper.TestableMapBase |
Pipeline |
Microsoft.BizTalk.TestTools.Pipeline.TestablePipelineBase |
- In main menu, click Build, and then click Rebuild Solution.
To create a unit test project
- On the File menu, choose "Add", and then choose "New Project...."
- In the New Project dialog box, expand "Installed", expand "Visual C#", and then choose "Test".
- From the list of templates, select "Unit Test Project".
- In the Name box, enter "UnitTestProject1", and then choose "OK".
- The "UnitTestProject1" project is added to the the "UnitTestingFeatureWithMaps" solution.
- In the "UnitTestProject1" project, for us to be able to accomplished testing BizTalk Schemas and Maps, we need to manually add the following references to the solution:
- Microsoft.BizTalk.TestTools - you can find this assembly in the following directory: "C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\PublicAssemblies\Microsoft.BizTalk.TestTools.dll"
- Microsoft.XLANGs.BaseTypes - you can find this assembly in the following directory: "C:\Program Files (x86)\Microsoft BizTalk Server 2013\Microsoft.XLANGs.BaseTypes.dll"
- BizTalk Server project assembly - in this case "UnitTestingFeatureWithMaps"
- You can accomplish this by:
- In Solution Explorer, select "References" in the "UnitTestProject1" project and then choose "Add Reference..." from the context menu.
We need two test class, one for testing the Schema and the other to test the map. We can use the UnitTest1.cs that was generated by the project template, but we should give the file and class more descriptive names. We can do that in one step by renaming the file in Solution Explorer.
Create the schema test class
- In Solution Explorer, select the "UnitTest1.cs" file in the "UnitTestProject1" project.
- From the context menu, choose "Rename", and then rename the file to "PersonOriginTest.cs". Choose Yes on the dialog that asks if you want to rename all references in the project to the code element 'UnitTest1'.
- Replace the exist code for this sample:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnitTestingFeatureWithMaps.Schemas;
namespace UnitTestProject1
{
/// <summary>
///This is a test class for PersonOriginTest and is intended
///to contain all PersonOriginTest Unit Tests
///</summary>
[TestClass()]
public class PersonOriginTest
{
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
/// <summary>
///A test for PersonOrigin Constructor
///</summary>
[TestMethod()]
public void PersonOriginConstructorTest()
{
PersonOrigin target = new PersonOrigin();
//=== Schema input file for validation ===//
string strSourcePO_XML = testContextInstance.TestDir + "..\\..\\..\\Files\\PersonOrigin.xml";
//=== Validate the XML Input message against the schema ===//
Assert.IsTrue(target.ValidateInstance(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML));
}
// <summary>
///A test for PersonOrigin Constructor
///</summary>
[TestMethod()]
public void PersonOriginWithoutPhoneCallsConstructorTest()
{
PersonOrigin target = new PersonOrigin();
//=== Schema input file for validation ===//
string strSourcePO_XML = testContextInstance.TestDir + "..\\..\\..\\Files\\PersonOrigin2.xml";
//=== Validate the XML Input message against the schema ===//
Assert.IsTrue(target.ValidateInstance(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML));
}
// <summary>
///A test for PersonOrigin Constructor
///</summary>
[TestMethod()]
public void PersonOriginWithoutZipConstructorTest()
{
PersonOrigin target = new PersonOrigin();
//=== Schema input file for validation ===//
string strSourcePO_XML = testContextInstance.TestDir + "..\\..\\..\\Files\\PersonOriginWithoutZip.xml";
//=== Validate the XML Input message against the schema ===//
Assert.IsTrue(target.ValidateInstance(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML));
}
}
}
Create the map test class
- In the "Add New Test" dialog box, select "Create a new Visual C# test project..." for Add to Test Project field. Select "Unit Test Wizard" in the Templates list, and then click OK.
- Right-click in "UnitTestProject1" project name, select "Add" and then select "New Item..."
- In the "Add New Item" dialog box, expand "Installed"and expand "Visual C# Items".
- From the list of items, select "Class" and in the Name box, enter "HowMapsWorksTest.cs", and then choose "OK".
- Replace the exist code for this sample:
using UnitTestingFeatureWithMaps.Maps;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using Microsoft.BizTalk.TestTools;
namespace UnitTestProject1
{
/// <summary>
///This is a test class for HowMapsWorksTest and is intended
///to contain all HowMapsWorksTest Unit Tests
///</summary>
[TestClass()]
public class HowMapsWorksTest
{
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
[TestMethod()]
public void HowMapsWorksMapTest()
{
/*********************************************************************************
* There is a bug with Map Unit Test inside Microsoft.BizTalk.TestTools.dll
* Microsoft had missed on to upgrade TestableMapBase class. They still using the
* BTSXslTransform instead of using XslCompiledTransform which will cause the
* TestMap() function to failed.
*
* The following code was the expected code for BizTalk Map unit testing
*********************************************************************************/
HowMapsWorks map = new HowMapsWorks();
//=== Use the HelloWorld sample directory path for the message files ===//
string strSourcePO_XML = testContextInstance.TestDir + "..\\..\\..\\Files\\PersonOrigin.xml";
string strDestInvoice_XML = testContextInstance.TestDir + "\\OUT\\PersonTarget2.xml";
//=== Test the map by using the TestMap method of the TestableMapBase class ===//
map.ValidateOutput = true;
map.TestMap(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.InputInstanceType.Xml,
strDestInvoice_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML);
//=== Output file should be created as a result of testing the map ===//
Assert.IsTrue(File.Exists(strDestInvoice_XML));
}
[TestMethod()]
public void HowMapsWorksWithoutPhoneCallsMapTest()
{
/*********************************************************************************
* There is a bug with Map Unit Test inside Microsoft.BizTalk.TestTools.dll
* Microsoft had missed on to upgrade TestableMapBase class. They still using the
* BTSXslTransform instead of using XslCompiledTransform witch will cause the
* TestMap() function to failed.
*
* The following code was the expected code for BizTalk Map unit testing
*********************************************************************************/
HowMapsWorks map = new HowMapsWorks();
//=== Use the HelloWorld sample directory path for the message files ===//
string strSourcePO_XML = testContextInstance.TestDir + "..\\..\\..\\Files\\PersonOrigin2.xml";
string strDestInvoice_XML = testContextInstance.TestDir + "\\OUT\\PersonTargetWithoutTotals.xml";
//=== Test the map by using the TestMap method of the TestableMapBase class ===//
map.ValidateOutput = true;
map.TestMap(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.InputInstanceType.Xml,
strDestInvoice_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML);
//=== Output file should be created as a result of testing the map ===//
Assert.IsTrue(File.Exists(strDestInvoice_XML));
#endregion
}
[TestMethod()]
public void HowMapsWorksWithoutZipMapTest()
{
/*********************************************************************************
* There is a bug with Map Unit Test inside Microsoft.BizTalk.TestTools.dll
* Microsoft had missed on to upgrade TestableMapBase class. They still using the
* BTSXslTransform instead of using XslCompiledTransform witch will cause the
* TestMap() function to failed.
*
* The following code was the expected code for BizTalk Map unit testing
*********************************************************************************/
HowMapsWorks map = new HowMapsWorks();
//=== Use the HelloWorld sample directory path for the message files ===//
string strSourcePO_XML = testContextInstance.TestDir + "..\\..\\..\\Files\\PersonOrigin.xml";
string strDestInvoice_XML = testContextInstance.TestDir + "\\OUT\\PersonTargetWithoutZip.xml";
//=== Test the map by using the TestMap method of the TestableMapBase class ===//
map.ValidateOutput = true;
map.TestMap(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.InputInstanceType.Xml,
strDestInvoice_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML);
//=== Output file should be created as a result of testing the map ===//
Assert.IsTrue(File.Exists(strDestInvoice_XML));
}
}
}
Building and Running the Unit Test
Use Test Explorer to run unit tests from Visual Studio unit test projects. You can also debug tests and analyze test performance and code coverage.
When you build the test project, the tests appear in Test Explorer and as you run, write, and rerun your tests, Test Explorer displays the results in default groups of Failed Tests, Passed Tests, Skipped Tests and Not Run Tests. You can change the way Test Explorer groups your tests.
If Test Explorer windows is not visible:
- On the Visual Studio main menu choose "Test", choose "Windows", and then choose "Test Explorer".
You can run all the tests in the solution, all the tests in a group, or a set of tests that you select. Do one of the following:
- To run all the tests in a solution, choose Run All.
- To run all the tests in a default group, choose Run... and then choose the group on the menu.
- Select the individual tests that you want to run, open the context menu for a selected test and then choose Run Selected Tests.
The pass/fail bar at the top of the Test Explorer window is animated as the tests run. At the conclusion of the test run, the pass/fail bar turns green if all tests passed or turns red if any test failed.
See more about Running Unit Tests with Test Explorer here.
Maps Unit Testing Workaround 1 (until the hotfix is unavailable)
Unfortunately there is a bug in BizTalk Server 2013 with Map Unit Test inside Microsoft.BizTalk.TestTools.dll, so each time we try to run the unit test for the map it give us the following error:
Microsoft.BizTalk.TestTools.BizTalkTestAssertFailException: Transform Failure
Result StackTrace: *
at Microsoft.BizTalk.TestTools.Mapper.TestableMapBase.PerformTransform(String inputXmlFile, String outputXmlFile)
* at Microsoft.BizTalk.TestTools.Mapper.TestableMapBase.TestMap(String inputInstanceFilename, InputInstanceType inputType, String outputInstanceFilename, OutputInstanceType outputType)
Microsoft had missed on to upgrade TestableMapBase class. They still using the BTSXslTransform instead of using XslCompiledTransform witch will cause the TestMap() function to failed.
You can find a wrapper (provide by shadabanwer) here: Map Unit test does not work in BizTalk 2013 because TestableMapBase class is not correct. However there is also a problem with schema (input and output) validation options... so I decide to recreated a new custom wrapper based on Microsoft.BizTalk.TestTools.dll and the solution provided by shadabanwer and fixed all the problems because validating the output instance generated by the map is an important step to validate your maps using Unit Testing. You can find this DLL here: BizTalk Server 2013: Wrapper classes to perform Unit Testing in Maps
You must use this workaround until Microsoft fix this bug.
So to be able to successfully test our maps we need to:
- In the "UnitTestProject1" project we need to manually add the following reference to the solution:
- SandroPereira.BizTalk.MapTestTools - again this assembly is available here: BizTalk Server 2013: Wrapper classes to perform Unit Testing in Maps
- And replace the exist code in the "HowMapsWorksTest.cs" for this sample:
using UnitTestingFeatureWithMaps.Maps;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
namespace UnitTestProject1
{
/// <summary>
///This is a test class for HowMapsWorksTest and is intended
///to contain all HowMapsWorksTest Unit Tests
///</summary>
[TestClass()]
public class HowMapsWorksTest
{
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
[TestMethod()]
public void HowMapsWorksMapTest()
{
HowMapsWorks map = new HowMapsWorks();
//=== Map input file instance to be mapped ===//
string strSourcePO_XML = testContextInstance.TestDir + "..\\..\\..\\Files\\PersonOrigin.xml";
//=== Path for the Map output file instance with the result of the transformation ===//
string strDestInvoice_XML = testContextInstance.TestDir + "\\Out\\PersonTarget2.xml";
//WORKAROUND SOLUTION to test maps
SandroPereira.BizTalk.MapTestTools.TestableMapBase mapper = new SandroPereira.BizTalk.MapTestTools.TestableMapBase();
mapper.Mapper = map;
mapper.Mapper.ValidateOutput = true;
//=== Test the map by using the TestMap method of a custom TestableMapBase class ===//
//=== that uses the XslCompiledTransform. This class is basically an improved ===//
//=== clone of the class present in the Microsoft.BizTalk.TestTools DLL ===//
mapper.TestMap(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.InputInstanceType.Xml,
strDestInvoice_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML);
//=== Output file should be created as a result of testing the map ===//
Assert.IsTrue(File.Exists(strDestInvoice_XML));
}
[TestMethod()]
public void HowMapsWorksWithoutPhoneCallsMapTest()
{
HowMapsWorks map = new HowMapsWorks();
//=== Map input file instance to be mapped ===//
string strSourcePO_XML = testContextInstance.TestDir + "..\\..\\..\\Files\\PersonOrigin2.xml";
//=== Path for the Map output file instance with the result of the transformation ===//
string strDestInvoice_XML = testContextInstance.TestDir + "\\Out\\PersonTarget2.xml";
//WORKAROUND SOLUTION to test maps
SandroPereira.BizTalk.MapTestTools.TestableMapBase mapper = new SandroPereira.BizTalk.MapTestTools.TestableMapBase();
mapper.Mapper = map;
mapper.Mapper.ValidateOutput = true;
//=== Test the map by using the TestMap method of a custom TestableMapBase class ===//
//=== that uses the XslCompiledTransform. This class is basically an improved ===//
//=== clone of the class present in the Microsoft.BizTalk.TestTools DLL ===//
mapper.TestMap(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.InputInstanceType.Xml,
strDestInvoice_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML);
//=== Output file should be created as a result of testing the map ===//
Assert.IsTrue(File.Exists(strDestInvoice_XML));
}
[TestMethod()]
public void HowMapsWorksWithoutZipMapTest()
{
HowMapsWorks map = new HowMapsWorks();
//=== Map input file instance to be mapped ===//
string strSourcePO_XML = testContextInstance.TestDir + "..\\..\\..\\Files\\PersonOriginWithoutZip.xml";
//=== Path for the Map output file instance with the result of the transformation ===//
string strDestInvoice_XML = testContextInstance.TestDir + "\\Out\\PersonTargetWithoutZip.xml";
//WORKAROUND SOLUTION to test maps
SandroPereira.BizTalk.MapTestTools.TestableMapBase mapper = new SandroPereira.BizTalk.MapTestTools.TestableMapBase();
mapper.Mapper = map;
mapper.Mapper.ValidateOutput = true;
//=== Test the map by using the TestMap method of a custom TestableMapBase class ===//
//=== that uses the XslCompiledTransform. This class is basically an improved ===//
//=== clone of the class present in the Microsoft.BizTalk.TestTools DLL ===//
mapper.TestMap(strSourcePO_XML,
Microsoft.BizTalk.TestTools.Schema.InputInstanceType.Xml,
strDestInvoice_XML,
Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML);
//=== Output file should be created as a result of testing the map ===//
Assert.IsTrue(File.Exists(strDestInvoice_XML));
}
}
}
Again, you must use this workaround until Microsoft fix this bug.
So if we perform the tests again, we will notice that the "Microsoft.BizTalk.TestTools.BizTalkTestAssertFailException: Transform Failure" is solved and the only error that is happening is about a Map output validation failure (intentionally present)
Maps Unit Testing Workaround 2 (add .testsettings file)
Unit tests in Visual Studio 2012 can be configured by using a .runsettings file. For example, you can change the .NET Framework on which the tests will be run, the directory where test results are delivered, and the data collected during a test run.
.runsettings is new in Visual Studio 2012. If you’re familiar with unit testing in previous versions of Visual Studio, you might know about .testsettings files. You can still use .testsettings in Visual Studio 2012, so any test configurations you wrote for previous editions will still work. But .testsettings can be used only to configure tests written for the MSTest adapter. By contrast, .runsettings can be used with any of the adapters built for the extensible unit test framework in Visual Studio 2012, such as xUnit.net and NUnit.
Tests that use .testsettings files might run more slowly than tests that use .runsettings files, or for which there is no configuration file at all.
You still need a .testsettings file for some kinds of tests:
- Tests that are deployed on a lab environment.
- Web performance and load tests.
- Customizing some types of diagnostic data adapters, such as IntelliTrace and ent log
- BizTalk Server maps (workaround)
Create a Test Settings File
So to fixed this problem using the Test Settings file, you could manually create a test settings file for example with notepad, let's call:
- Local.testsettings
And add the following content:
<?xml version="1.0" encoding="UTF-8"?>
<TestSettings name="Local" id="6bfb00a1-f0ec-4f57-81ab-89ee852f1e49" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>These are default test settings for a local test run.</Description>
<Deployment enabled="false" />
<Execution>
<TestTypeSpecific />
<AgentRule name="Execution Agents">
</AgentRule>
</Execution>
</TestSettings>
Or you can add a new test settings file directly from your BizTalk solution:
- Right click on the BizTalk solution name: “Solution ‘UnitTestingFeatureWithMaps’ (2 projects)”, and select “Add” and them “New Item…”
- In the “Add New Item – Solution Items” dialog box, expand "Installed" and then choose "Test Settings".
- From the list of items, select "Test Settings".
- In the Name box, enter "TestSettings.testsettings", and then click "Add".
- This will open a new window for us to specify the settings of the test settings file, just leave the default setting by click “Close”.
How do I use a test settings file?
Add test settings files to your solution, and then select the one you want to use. You can add more than one test settings file if you want to be able to switch quickly between different settings.
- On the Visual Studio main menu choose "Test", choose "Test Settings", and then choose "Test Settings File".
- In the "Open Setting File" window select the test setting file that we previous create: "Local.testsettings"or "TestSettings.testsettings"
So if we perform the tests again, we will notice that the "Microsoft.BizTalk.TestTools.BizTalkTestAssertFailException: Transform Failure" is solved and the only error that is happening is about a Map output validation failure (intentionally present)
Source Code
This sample can be found and downloaded in Microsoft Code Gallery:
- BizTalk Server 2013: Using the Unit Testing Feature with Schemas and Maps
- BizTalk Server 2013: Wrapper classes to perform Unit Testing in Maps
See Also
The following resources will provide useful information on unit testing BizTalk Server projects:
- BizTalk Server - Unit Testing
- Create a Load Test to Perform Multiple Unit Tests Simultaneously
- BizTalk Server 2013: Test BizTalk artifacts with Visual Studio 2012
- BizTalk Server 2010: Step-by-Step to implement Unit Testing in Schemas and Maps
Another important place to find a huge amount of BizTalk related articles is the TechNet Wiki itself. The best entry point is BizTalk Server Resources on the TechNet Wiki.