Table of Contents

Introduction

With the advent of agile methodology for the project delivery, a scenario where the code changes from multiple developers need to be built and tested on the build server presents itself very frequently even for multiple times even in a single day. And testing the build includes a lot of manual work right from building the code to verifying the deployment of the code on the build server. Continuous Integration and Deployment provide a way of coping up with this demand of the testing and deployment of the code to the environments like Preproduction, Quality Assurance servers and even to the production environment. Continuous integration and deployment focus on automating following steps using various CI CD tools like Visual Studio Team Services (VSTS), Jenkins etc.

  1. Fetch the code from the Source Control
  2. Build the code
  3. Run Unit Tests
  4. Generate The Deployment Packages
  5. Install And Deploy the Packages 
  6. Run the Deployment Verification/Integration Tests
  7. Push the MSI to the next target Server.

Steps 1 to 6 are done on the build server with a run restriction based upon the success of the predecessor steps. Once the Steps 1 through 6 are executed successfully, the installer package can be released to the immediate higher environment where the CI/CD tool deploys the installer package and then hands over the control for actual testing to the Testing Teams. The successful testing then can prompt the movement of the package to the next higher environment and so on till the code actually reaches the production environment.

Back To top 


BizTalk CI CD 

This concept can be applied to the BizTalk solutions. The CI CD approach can be used to automate the building and deployment of the BizTalk code across multiple environments. The CI CD approach for BizTalk applications is a bit different as the deployment of the BizTalk applications is different from normal .NET apps. Various tools aid in setting up BizTalk CI CD right from the Source Control to the deployment. This entire process can be achieved using the Team Foundation Server, Visual Studio Team Services or other open source application like Jenkins. This article deals with setting up the CI CD for BizTalk using Jenkins in combination with PowerShell scripts, MSBuild and Windows batch files. Following tools are used to set up the CI CD cycle for BizTalk

  1. GIT Repository - Used for Source Control (Build Server Should have the GIT Command Line Tools Installed to Pull The Code from GIT)
  2. Visual Studio - Used to Build BizTalk Application
  3. BizUnit and Visual Studio Testing Framework - Used to write and execute the Unit Test Cases for the BizTalk schemas, Maps and Helper class Methods
  4. BizTalk Deploymentenvironments. The CI CD approach for BizTalk applications is a bit different as the deployment of the BizTalk applications is different from normal .NET apps. Various tools aid in setting up BizTalk CI CD right from the Source Control to the deployment. This entire process can be achieved using the Team Foundation Server, Visual Studio Team Services or other open source application like Jenkins. This article deals with setting up the CI CD for BizTalk using Jenkins in combination with PowerShell scripts, MSBuild and Windows batch files. Following tools are used to set up the CI CD cycle for BizTalk

      Framework - Used to create the mMSIinstaller package for the BizTalk application.
    1. NUnit - Used to run Post Deployment Integration tests
    2. Jenkins- Used as the CI CD server. To automate the building and testing of the BizTalk applications.

    Back To Top


    CICD Flow

    Following flowchart describes the flow for the build server pipeline tasks related to the CICD.

    Back To Top


    Sample BizTalk Application

    The application used in this demonstration is a simple application which takes the first name and the last name of the person and returns the full name by appending the first and the last name. The BizTalk application is invoked through a WCF service. Following are the input and the output schemas used in the app.

    1. Input.xsd



        <xs:element name="Req">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="FirstName" type="xs:string" />
              <xs:element name="LastName" type="xs:string" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:schema>




    2. Output.xsd 



        <xs:element name="Resp">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="FullName" type="xs:string" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:schema>

    The BizTalk application project also has a unit test helper and unit tests project which contains the unit tests to test the map which is used to transform the input to output. The Unit Test projects take the help of the BizUnit framework and the Visual Studio Testing framework to run the unit tests. Following piece of code shows the implementation of the classes from the BizUnit framework and how they can be used to create the method to test the Maps in the sample BizTalk application.

    01.using System.Collections.Generic;
    02.using BizUnit.TestSteps.Common;
    03.using BizUnit.TestSteps.ValidationSteps.Xml;
    04.using BizUnit.TestSteps.File;
    05.using Microsoft.BizTalk.TestTools.Mapper;
    06.using BizUnit.Core.TestBuilder;
    07.namespace SampleBTApp.TestHelper
    08.{
    09.    public static class MapTestHelpers
    10.    {
    11.        public static SampleBTApp.TestHelper
    08.{
    09.    public static class MapTestHelpers
    10.    {
    11.        public static void MapTest(string inputMessageFolderPath, string outputMessageFolderPath, TestableMapBase target, string sourceFile, SchemaDefinition sourceSchema, string destinationFile, SchemaDefinition destinationSchema, List<XPathDefinition> xpathList)
    12.        {
    13.            ValidateSouceMessage(inputMessageFolderPath, sourceFile, sourceSchema);
    14. 
    15.            string inputMessagePath = inputMessageFolderPath + sourceFile;
    16.            string outputMessagePath = outputMessageFolderPath + destinationFile;
    17. 
    18.            target.ValidateInput = false;
    19.            target.ValidateOutput = false;
    20.            target.TestMap(inputMessagePath, Microsoft.BizTalk.TestTools.Schema.InputInstanceType.Xml, outputMessagePath, Microsoft.BizTalk.TestTools.Schema.OutputInstanceType.XML);
    21. 
    22. 
    23.        }
    24. 
    25.        public static void ValidateSouceMessage(string inputMessageFolderPath, string inputFile, SchemaDefinition sourceSchema)
    26.        {
    27.            FileReadMultipleStep fileReadStep = new FileReadMultipleStep();
    28. 
    29.            fileReadStep.DeleteFiles = false;
    30.            fileReadStep.DirectoryPath = inputMessageFolderPath;
    31.            fileReadStep.SearchPattern = inputFile;
    32.            fileReadStep.FailOnError = true;
    30.            fileReadStep.DirectoryPath = inputMessageFolderPath;
    31.            fileReadStep.SearchPattern = inputFile;
    32. lock;">33.            fileReadStep.ExpectedNumberOfFiles = 1;
    34. 
    35.            XmlValidationStep inputValidationStep = new XmlValidationStep();
    36.            inputValidationStep.XmlSchemas.Add(sourceSchema);
    37. 
    38.            fileReadStep.SubSteps.Add(inputValidationStep);
    39.            TestCase inValTestCase = new TestCase();
    40.            inValTestCase.Name = "Validate Input Message";
    41.            inValTestCase.ExecutionSteps.Add(fileReadStep);
    42. 
    43.            BizUnit.Core.TestRunner testRunner = new BizUnit.Core.TestRunner(inValTestCase);
    44.            testRunner.Run();
    45. 
    46.             
    47.        }
    48. 
    49. 
    50.        public static void ValidateDestinationMessage(string OutoutputMessageFolderPath, string outputFile, SchemaDefinition destinationSchema, List<XPathDefinition> xpathList)
    51.        {
    52.            FileReadMultipleStep fileReadStep = new FileReadMultipleStep();
    53.            fileReadStep.DeleteFiles = false;
    54.            fileReadStep.FailOnError = true;
    55.            fileReadStep.DirectoryPath = OutoutputMessageFolderPath;
    56.            fileReadStep.SearchPattern = outputFile;
    57.            fileReadStep.ExpectedNumberOfFiles = 1;
    58. 
    59. 
    60.            XmlValidationStep validateOutPutStep = new XmlValidationStep();
    61.            validateOutPutStep.XmlSchemas.Add(destinationSchema);
    62. 
    63.            foreach( var xpath in xpathList)
    64.            {
    65.                validateOutPutStep.XPathValidations.Add(xpath);
    66.            }
    67. 
    68.            fileReadStep.SubSteps.Add(validateOutPutStep);
    69. 
    70.            TestCase outValTestCase = new TestCase();
    71.            outValTestCase.Name= "Validate Output Message";
    72.            outValTestCase.ExecutionSteps.Add(fileReadStep);
    73. 
    74.            BizUnit.Core.TestRunner testRunner = new BizUnit.Core.TestRunner(outValTestCase);
    75.            testRunner.Run();
    76. 
    77. 
    78. 
    79.        }
    80.    }
    81.}


    Following class shows how the unit test cases written to test the maps.

    01.using System;
    02.using Microsoft.VisualStudio.TestTools.UnitTesting;
    03.using SampleBTApp.TestHelper;
    04.using BizUnit.TestSteps.ValidationSteps.Xml;
    05.using Microsoft.BizTalk.TestTools.Mapper;
    06.using SampleBTApp.Maps;
    07.using System.Collections.Generic;
    08.using BizUnit.TestSteps.Common;
    09.namespace SampleBTApp.UnitTests
    10.{
    11.    [TestClass]
    12.    public class MapTests
    13.    {
    14.        private const string InputFileDirectory = @"E:\BizTalkCICDUsingJenkins\BizTalkApp\SampleBTApp\SampleBTApp.UnitTests\SampleMessages\In\";
    15.        private const string OutputFileDirectory = @"E:\BizTalkCICDUsingJenkins\BizTalkApp\SampleBTApp\SampleBTApp.UnitTests\SampleMessages\Out\";
    16. 
    17.        SchemaDefinition sourceSchema = new SchemaDefinition()
    18.        {
    19.            XmlSchemaNameSpace = "http://SampleBTApp.Schemas.Input",
    20.            XmlSchemaPath = @"E:\BizTalkCICDUsingJenkins\BizTalkApp\SampleBTApp\SampleBTApp.Schemas\Input.xsd"
    21. 
    22.        };
    23. 
    24.        SchemaDefinition destinationSchema = new SchemaDefinition()
    25.        {
    26.            XmlSchemaNameSpace = "http://SampleBTApp.Schemas.Output",
    27.            XmlSchemaPath = @"E:\BizTalkCICDUsingJenkins\BizTalkApp\SampleBTApp\SampleBTApp.Schemas\Output.xsd"
    28.        };
    29. 
    30.        [TestMethod]
    31.        public void TestTransform_Input_To_OutputMap()
    32.        {
    33.            var inputSchema = sourceSchema;
    34.            var outputSchema = destinationSchema;
    35.            const string inputFile = "Input.xml";
    36.            const string outputFile = "Output.xml";
    37.            const string fullNameXpath = "/*[local-name()='Resp' and namespace-uri()='http://SampleBTApp.Schemas.Output']/* [local-name()='FullName' and namespace-uri()='']";
    38. 
    39.            List<XPathDefinition> xpathList = new List<XPathDefinition>()
    40.            {
    41.                new XPathDefinition()
    42.                {
    43.                    XPath = fullNameXpath,
    44.                    Value = "Mandar Dharmadhikari"
    45. 
    46.                }
    47.            };
    48. 
    49.            TestableMapBase target = new Maps.Input_To_Output();
    50.            MapTestHelpers.MapTest(InputFileDirectory, OutputFileDirectory, target, inputFile, sourceSchema, outputFile, destinationSchema, xpathList);
    51.             
    52.        }
    53.    }
    54.}

    These unit tests can be run from the Visual StileDirectory, OutputFileDirectory, target, inputFile, sourceSchema, outputFile, destinationSchema, xpathList);