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.
- Fetch the code from the Source Control
- Build the code
- Run Unit Tests
- Generate The Deployment Packages
- Install And Deploy the Packages
- Run the Deployment Verification/Integration Tests
- 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.
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
- GIT Repository - Used for Source Control (Build Server Should have the GIT Command Line Tools Installed to Pull The Code from GIT)
- Visual Studio - Used to Build BizTalk Application
- BizUnit and Visual Studio Testing Framework - Used to write and execute the Unit Test Cases for the BizTalk schemas, Maps and Helper class Methods
- 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.
- NUnit - Used to run Post Deployment Integration tests
- Jenkins- Used as the CI CD server. To automate the building and testing of the BizTalk applications.
CICD Flow
Following flowchart describes the flow for the build server pipeline tasks related to the CICD.
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.
- Input.xsd
<
xs:schema
xmlns
=
"http://SampleBTApp.Schemas.Input"
xmlns:b
=
"http://schemas.microsoft.com/BizTalk/2003"
targetNamespace
=
"http://SampleBTApp.Schemas.Input"
xmlns:xs
=
"http://www.w3.org/2001/XMLSchema"
>
<
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
>
- Output.xsd
<
xs:schema
xmlns
=
"http://SampleBTApp.Schemas.Output"
xmlns:b
=
"http://schemas.microsoft.com/BizTalk/2003"
targetNamespace
=
"http://SampleBTApp.Schemas.Output"
xmlns:xs
=
"http://www.w3.org/2001/XMLSchema"
>
<
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);