BizTalk Server 2013: Step-by-Step to implement Unit Testing in Schemas and Maps

Posted: August 28, 2014  |  Categories: BizTalk Maps Schemas

To implement BizTalk Server 2013 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”.
BizTalk Server 2013 Project Designer Deployment property
  • Close the project properties page saving the changes.

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”.
BizTalk Server 2013 New Unit Test Project
  • In the Name box, enter “UnitTestProject1”, and then choose “OK”.
  • The “UnitTestProject1” project is added to 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.

To unit test a schema you can leverage the unit test framework in Visual Studio. In the Unit Test Class you can test methods like below for validating XML document instance:

/// <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));
}

To unit test a map you can leverage the unit test framework in Visual Studio. In the Unit Test Class you can test method like below for testing a mapping:

[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 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\\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));
}

Maps Unit Testing Workaround (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 gives 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 which will cause the TestMap() function to fail.
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:

[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));
}

Check the full detailed article here: BizTalk Server 2013: Step-by-Step to implement Unit Testing in Schemas and Maps

You can download Full sample here:
BizTalk Server 2013: Using the Unit Testing Feature with Schemas and MapsBizTalk Server 2013: Using the Unit Testing Feature with Schemas and Maps
GitHub

Author: Sandro Pereira

Sandro Pereira lives in Portugal and works as a consultant at DevScope. In the past years, he has been working on implementing Integration scenarios both on-premises and cloud for various clients, each with different scenarios from a technical point of view, size, and criticality, using Microsoft Azure, Microsoft BizTalk Server and different technologies like AS2, EDI, RosettaNet, SAP, TIBCO etc. He is a regular blogger, international speaker, and technical reviewer of several BizTalk books all focused on Integration. He is also the author of the book “BizTalk Mapping Patterns & Best Practices”. He has been awarded MVP since 2011 for his contributions to the integration community.

14 thoughts on “BizTalk Server 2013: Step-by-Step to implement Unit Testing in Schemas and Maps”

  1. Hi

    I’m noticing a lot of confusion about testing maps with BT 2013. I just reference a testsettings file which forces the tests to run in 32-bit mode and everything seems fine.
    What do you think to this approach?

    1. Hi Paul,

      Supposedly Test Settings configurations file:
      – Visual Studio 2010 – it was specified in a .testsettings file and it had GUI interaction and xml templating for customization. This can still be used in VS2012 via a ForcedLegacyMode element in the xml, however this is noted as a performance inhibitor for the test runner.
      •- Visual Studio 2012 – It’s now specified in a .runsettings file, with no GUI config editting, IntelliSense support or item creation templating.

      If we add a .runsettings file to our test project it doesn’t work!

      However if we take the .testsettings file that was generated for example in Visual Studio 2010/BizTalk Server 2010 and add this file to our Test project in Visual Studio 2012/BizTalk Server 2013 it works and solve the problem, don’t know why but is other workaround to solve this problem.

  2. Hello Sandro, I was trying to test a schema that imports other schemas with the validate method but it fails with any valid document (the documents were validated in Visual Studio). Have you ever had the same problem?

      1. I’ve no idea if this helps butthis is the code I recently wrote to ensure when we unit test a map it can be run in an environment with no artefacts in the GAC.

        The built in validation of a map seemed to fail when the schemas assemblies weren’t in the GAC.

        A build server should have no artefacts in the GAC so I’ve been trying a few things like this and MS Fakes recently to help us run our tests on a build server.

        All references do need to be in the Bin folder but they tend to be there when you have a reference to the map you’re testing

        Calling code:

        BizTalkMapTestHelper.TestMap(map, inputFileName);

        Helper class:

        ///

        /// A collection of methods to help with testing maps.

        ///

        public static class BizTalkMapTestHelper

        {

        public static string TestMap(TestableMapBase map, string inputFilename)

        {

        ValidateInput(map, inputFilename);

        var destinationFilename = Path.GetTempFileName();

        map.ValidateInput = false;

        map.ValidateOutput = false;

        map.TestMap(inputFilename, InputInstanceType.Xml, destinationFilename, OutputInstanceType.XML);

        ValidateOutput(map, destinationFilename);

        return destinationFilename;

        }

        private static void ValidateInput(TestableMapBase map, string fileNameOfXmlToValidate)

        {

        var schemas = map.SourceSchemas;

        var attrs = GetSchemaReferenceAttributes(map);

        ValidateInstance(fileNameOfXmlToValidate, schemas, attrs);

        }

        private static void ValidateOutput(TestableMapBase map, string fileNameOfXmlToValidate)

        {

        var schemas = map.TargetSchemas;

        var attrs = GetSchemaReferenceAttributes(map);

        ValidateInstance(fileNameOfXmlToValidate, schemas, attrs);

        }

        private static IEnumerable GetSchemaReferenceAttributes(TestableMapBase map)

        {

        var attrs = System.Attribute.GetCustomAttributes(map.GetType(), typeof(Microsoft.XLANGs.BaseTypes.SchemaReferenceAttribute)).Cast();

        return attrs;

        }

        private static void ValidateInstance(string fileNameOfXmlToValidate, IEnumerable schemas, IEnumerable attrs)

        {

        string validationErrors = string.Empty;

        XmlSchemaSet schemaSet = new XmlSchemaSet();

        foreach (var schema in schemas)

        {

        schemaSet.Add(LoadSchema(schema, attrs));

        }

        XDocument doc = XDocument.Load(fileNameOfXmlToValidate);

        doc.Validate(schemaSet, (o, e) => { validationErrors += e.Message + Environment.NewLine; });

        if (validationErrors.Any())

        {

        throw new XmlSchemaValidationException(validationErrors);

        }

        }

        private static XmlSchema LoadSchema(string schemaName, IEnumerable attrs)

        {

        Type schemasType = attrs.Single(a => a.Reference == schemaName).Type;

        var schemaBase = Activator.CreateInstance(schemasType) as Microsoft.XLANGs.BaseTypes.SchemaBase;

        if (schemaBase == null)

        {

        throw new Exception(“Could not cast to a SchemaBase”);

        }

        return schemaBase.Schema;

        }

        }

  3. I ran into an issue involving custom script functoids calling .Net components. The current Sandro fix omits the addition of extension objects. By creating a fake assembly (see https://truenorthit.co.uk/2014/11/17/unit-testing-biztalk-maps-external-functoids/) I got it working. Code looks like this:

    //use shims to change the compiled transform behavior to accept xslt arguments
    using (ShimsContext.Create())
    {
    System.Xml.Xsl.Fakes.ShimXslCompiledTransform.AllInstances.TransformXmlReaderXmlWriter = (xslCompiledTransform, xmlReader, xmlWriter) =>
    {
    xslCompiledTransform.Transform(xmlReader, map.Mapper.TransformArgs, xmlWriter);
    };

    //execute the map
    map.Mapper.ValidateInput = testcase.validateinput;
    map.Mapper.ValidateOutput = testcase.validateoutput;
    var inputinstancetype = (Microsoft.BizTalk.TestTools.Schema.InputInstanceType)testcase.inputinstancetype;
    var outputinstancetype = (Microsoft.BizTalk.TestTools.Schema.OutputInstanceType)testcase.outputinstancetype;
    string inputinstancefilelocation = System.IO.Path.Combine(BASEPATH, subfolder, string.Concat(mapname, “_”, testcase.name, “_input.” + testcase.inputinstancetype.ToString().ToLower()));
    string outputinstancefilelocation = System.IO.Path.Combine(BASEPATH, subfolder, string.Concat(mapname, “_”, testcase.name, “_output.” + testcase.outputinstancetype.ToString().ToLower()));

    try
    {
    map.TestMap(inputinstancefilelocation, inputinstancetype, outputinstancefilelocation, outputinstancetype);
    }
    catch (Microsoft.BizTalk.TestTools.BizTalkTestAssertFailException btafe)
    {
    Assert.Fail(“Mapping ” + mapname + ” failed in testcase ” + testcase.name + “.” + Environment.NewLine + btafe.ToString());
    }

    etc..
    }

Leave a Reply

Your email address will not be published. Required fields are marked *

turbo360

Back to Top