Integration test

We have a very simple BizTalk application, the calulator sample application (see the source code). The application takes a message with two integers and returns another message with the same content, plus the sum of the numbers. Messages are sent to a file share path, and the responses are returned to another file share path.

UnitTest1.png

To test this application we will create a test that act as the client application and also verifies the response message.

For this project, the tests will be located in a separate solution. This allows the testers to work on the tests without the burden of opening all the BizTalk projects. For very small teams you might want to have the integration tests in the same solution as you BizTalk projects.

Start by creating a new solution, called IntegrationTests. Then add a new Unit Test Project. We are using the “Unit Test Project” template even if we are writing integration tests. In this example, we are going to create one test project per BizTalk application. However, in scenarios that are more complex an integration test may span multiple applications, so group your tests according to your needs.


IntegrationTest1.png

Create folders for the test data, and add the request message and the expected response message. Set the build action to "Embedded Resource". This will put the XML files into the assembly (.dll file), and is important when we want to automate testing using test agents.

IntegrationTest2.png

This is the test code. It will read the embedded XML file, and write it to the location where BizTalk listens for the file. And then, poll the output folder until BizTalk returns the response. The last step is comparing the expected output to the actual output. If they are the same, the test succeeds.

See comments in the code for more details.

namespace IntegrationTests.Calculator
{
  using System;
  using System.IO;
  using System.Linq;
  using System.Reflection;
  using System.Threading;
  using System.Xml.Linq;
  using Microsoft.VisualStudio.TestTools.UnitTesting;

  /// <summary>
  /// Runs a test of the Calculator BizTalk application where everything is
  /// supposed to work without errors (happy flow).
  /// </summary>
  [TestClass]
  public class HappyFlow
  {
    /// <summary>
    /// The file share where request messages are sent.
    /// </summary>
    private const string SendToFolder = @"\\btap1\TestData\Calculator\In";

    /// <summary>
    /// The file share where response messages are read from.
    /// </summary>
    private const string ReceiveFromFolder = @"\\btap1\TestData\Calculator\Out";
    
    /// <summary>
    /// The entry point for the test.
    /// </summary>
    [TestMethod]
    [Timeout(30000)]
    public void HappyFlowTest()
    {
      string id;
      string responseFilename;
      XDocument request;
      XDocument expectedResponse;
      XDocument actualResponse;
      XNamespace ns1;
      XNamespace ns2;

      // Define the namespaces we need.
      ns1 = "http://contoso.com/biztalkdemo/addrequest/v1";
      ns2 = "http://contoso.com/biztalkdemo/addresponse/v1";

      // Load the docuemnt templates.
      request = XDocument.Load(this.GetResourceStream("AddRequest.xml"));
      expectedResponse = XDocument.Load(this.GetResourceStream("AddResponse.xml"));

      // Create a new unique ID
      id = Guid.NewGuid().ToString();

      // Replace the ID in our messages in order to
      // create a uniqe message for each test run.
      request.Descendants(ns1 + "UnitOfWorkID").First().Value = id;
      expectedResponse.Descendants(ns2 + "UnitOfWorkID").First().Value = id;

      // Send the request message to BizTalk, using the ID as the file name.
      request.Save(Path.Combine(SendToFolder, id + ".xml"));

      // The BizTalk application outputs the original filename,
      // so we know what to look for.
      responseFilename = Path.Combine(ReceiveFromFolder, id + ".xml");

      // Poll for the file. If BizTalk fails and never outputs the
      // file, the test will stop on time-out.
      while (!File.Exists(responseFilename))
      {
        Thread.Sleep(1000);
      }

      // Load the actual response.
      actualResponse = XDocument.Load(responseFilename);

      // Compare the actual and expected XML documents.
      // Note that the DeepEquals method is sensitive to syntax differences.
      // You may need to adjust the expected message for the comparison to work.
      Assert.IsTrue(XNode.DeepEquals(actualResponse, expectedResponse));
      
      // Cleanup the file
      File.Delete(responseFilename);
    }

    /// <summary>
    /// Get the stream of an embedded file.
    /// </summary>
    /// <param name="name">The file name.</param>
    /// <returns>The stream of the embedded file.</returns>
    private Stream GetResourceStream(string name)
    {
      Assembly asm;
      Stream s;

      asm  = Assembly.GetExecutingAssembly();
      s = asm.GetManifestResourceStream("IntegrationTests.Calculator.TestData.HappyFlow." + name);

      return s;
    }
  }
}

Run the test form Visual Studio using Test Explorer.

IntegrationTest3.png

Previous Next

Last edited Mar 4, 2014 at 10:37 AM by hallis, version 12