« TestDriven.NET Tryout | Main | Mort or Elvis »
As many of you know, there are basically two ways to test custom Pipelines and custom Pipeline Components in BizTalk Server:
Option 1 is required, definitely a needed option, but it is inconvenient, at the least, for agile development: it is slow, cumbersome, and hard to automate. Option 2 is easier and faster, but it's also inconvinient to automate.
So I had been looking at ways to automate the testing of pipelines and pipeline components, and ran across this article, explaining how to use mocks to unit test pipeline components. Neat, but inconvenient as well. Furthermore, it does not allow you to test pipeline components inside a real pipeline, which is sometimes necessary to ensure your component works well with the built-in components in BizTalk (disassembler in particularly can be pretty picky).
I realized then that MS already provided most of what you needed to test pipeline components in a better way, and one which was possible to embed inside NUnit tests (or whatever unit testing framework you use): Pipeline.exe relies on a set of helper components in the PipelineObjects.dll assembly included with the SDK, which does the heavy work of mocking the most important BizTalk objects that execute pipelines, such as IPipelineContext, IBaseMessage and IBaseMessageFactory and so on. I figured that, with a nicer API built on top of this, I could come up with something that really made it easier to test your pipeline components in a more agile manner, and that complemented the core unit tests you are creating for internal functionality.
So I've been working on this for the past couple of days and I've already have a working implementation. Here's an example of what it might look like:
/// <summary>
/// Tests that we can execute successfully a loaded pipeline
/// with a flat file as input
/// </summary>
[Test]
public void Test_ExecuteOK_FF()
{
ReceivePipelineWrapper pipeline =
PipelineFactory.CreateReceivePipeline(typeof(CSV_FF_RecvPipeline));
// Create the input message to pass through the pipeline
Stream stream = DocLoader.LoadStream("CSV_FF_RecvInput.txt");
IBaseMessage inputMessage = MessageHelper.CreateFromStream(stream);
inputMessage.BodyPart.Charset = "UTF-8";
// Add the necessary schemas to the pipeline, so that
// disassembling works
pipeline.AddDocSpec(typeof(Schema3_FF));
// Execute the pipeline, and check the output
MessageCollection outputMessages = pipeline.Execute(inputMessage);
Assert.IsNotNull(outputMessages);
Assert.IsTrue(outputMessages.Count > 0);
}
The code above does the following:
It's cetainly not a lot of code, and personally I think the API is looking pretty nice right now. So far, I got it working with the following scenarios:
Here's another example, this time of doing multiple document batching into an envelope using the XML Assembler:
/// Tests we can execute a send pipeline with
/// multiple input messages and an envelope
public void Test_ExecuteOK_MultiInput()
SendPipelineWrapper pipeline =
PipelineFactory.CreateSendPipeline(typeof(Env_SendPipeline));
string body =
@"<o:Body xmlns:o='http://SampleSchemas.SimpleBody'>
this is a body</o:Body>";
MessageCollection inputMessages = new MessageCollection();
inputMessages.Add(MessageHelper.CreateFromString(body));
// assembling works
pipeline.AddDocSpec(typeof(SimpleBody));
pipeline.AddDocSpec(typeof(SimpleEnv));
// we get a single message batched with all the
// messages grouped into the envelope's body
IBaseMessage outputMessage = pipeline.Execute(inputMessages);
Assert.IsNotNull(outputMessage);
using ( StreamReader reader = new StreamReader(outputMessage.BodyPart.Data) )
// d contains the entire output message
string d = reader.ReadToEnd();
One important difference with working with the API I'm creating and pipeline.exe is that the API is meant to be used with existing biztalk artifacts, which you can create with regular biztalk projects (though they don't need to be deployed to use them). Pipeline.exe, on the other hand, works with the raw *.btp and *.xsd files, which is simpler for some things, but far more inconvinient for testing, at least in my opinion.
I should be ready to post this in a few days, as I still need to test it more throughly and fix a few things, but if anyone is interested, let me know and I'll pass on what code I have right now. Do note I'm implementing this for BTS06 only, though I see no reason why you couldn't port it to BTS04!
Tomas Restrepo is a software developer located in Colombia, South America. His interests include .NET, Connected Systems, PowerShell and lately dynamic programming languages. More...
email: tomas@winterdom.com msn: tomasr@passport.com
Copyright © 2002-2008, Tomas Restrepo.
Powered by: newtelligence dasBlog 2.2.8279.16125