On the ‘Opacity’ of Orchestrations
Richard Hallgren recently sent me a link to a question that was posted on StackOverflow dealing with “Mocking Web Services consumed by Biztalk Request Response ports” and asked for my thoughts on the subject as BizUnit and BizUnitExtensions were both mentioned. There were a couple of posts there at the time, one questioning why bother, another directing him to use SoapUI and another really good reply by David Hall on the topic of mock BizTalk adapters (which I want to talk about in some more depth later). David’s points helped me crystallize some of my thoughts on the subject of testing orchestrations and I replied there and figured that it was a good subject to blog about in more detail.
David raised the point about there not being real ‘unit tests’ in BizTalk (at least not unit tests in the purist sense of the word) and that the ‘opaque’ nature of orchestrations made it very difficult to actually ‘unit’ test them. He did also raise the point about BizUnit being a bit of a misnomer (the ‘Unit’ part being somewhat misleading to someone new to BizTalk). I do agree with the points he raises there. Here are some of the things I wrote there and which I will expand upon to some extent in this post and some extra points.
One approach which I have recently got sold on is the use of mock object frameworks (such as MoQ, RhinoMocks, TypeMock and NMock2). I used NMock2 in my last ASP.NET project and have recently started with MoQ which i think is much better and i’m really getting into the lambdas.. they make expressing intent so much more concise. I’ll write a bit more about how I’m using them in another post, but suffice to say here that, although I havent tried it myself, several Biztalk folk have successfully used mock objects to test pipeline components.
Orchestrations unfortunately, in this respect (of being able to completely control what their dependencies are and ‘faking’ the behavior of the dependency) can be considered opaque. But there are good reasons for that.
a) Because of the huge subscription system in the message box – that orchestrations use when being activated etc, it is not possible to fire up some “virtual” process to host the orchestration (I think Tomas’s Pipeline Testing Library does something along these lines for pipeline components, but I havent had the opportunity to use that so far although i have heard good things about it).
(b) Now for arguments sake, lets assume you could write such a virtual host. Now how would this virtual process handle persistence and dehydration?. I’d wager that people using WF would have the same problem in trying to test the workflow fully. (Soon after writing this I came across Matt Milners MSDN article on unit testing workflows, but workflows are just CLR code)
(c) Although you can see the C# equivalent of the ODX, we dont develop with the C# equivalent directly, so there is no way we can “inject” a mock interface into the orchestration code. Orchestrations are at a higher level of abstraction than ‘normal’ code so while you may declare variables and use them in expression shapes etc, its not the same as writing getters and setters in regular C#.
(d) An orchestration is not really a “unit”. It is a composite element. The units are the messages going to and from the message box and the external components called through expression shapes.So even if you could inject a mock webservice interface you cannot inject mock message boxes and correlation sets and other things.
Of course, it may be possible to get more testability for orchestrations in future versions of the product (beyond v.2009), but this is the situation now. If there are other approaches you use to dealing with the innards of orchestrations then do let me know.
In terms of getting more info on the orchestration itself, one thing that can be done (and i’ve been considering an addition to the BizUnitExtensions library to do this) is to link in with the OrchestrationProfiler tool a(s that tool gives a pretty detailed report of all the shapes ). Now from the BizUnit test we can verify that individual steps were executed and perhaps also check the time it took for execution. This is a bit like setting expectations for mock objects. This could go quite far in making the orchestration a bit more of a white box.Also considering that the orchestration debugger shows a lot of the variable values, surely it must be possible to get that info via an API (one hopes!!) to show what the values of variables were at a given point for a given instance.
One thing which a lot of people get hung up on is terminology (unit tests vs. functional tests). I dont know why its hard for some folk to accept that the granularity of a unit is entirely subjective and depends a lot on the system. For a system like Biztalk, especially with orchestrations, in my opinion, the unit of testing includes the pickup of the message from the source, the processing and its dispatch. A functional test will expand on that to include things like getting the data into the source and an integration test will span the entire system, and of course, since the solutions built with Biztalk are quite different this definition of whats involved in each category of testing needs to be ‘adapted’ for each project.
Back to Richard’s question though, my previous dev team had a solution. Basically what we did was to write a generic configurable HttpHandler that parsed incoming service requests and returned pre-set responses. The response sent back was configurable based on conditions such as XPath. In the BUILD and DEV binding files, the webservice end point was the mock. This worked brilliantly in isolating the BUILD and DEV environments from the actual third party webservices. This also helped in a “contract first” approach where we built the mock endpoint and the orch developer used it while the webservice author went ahead and built the actual service behind the endpoint. In my next post, I’ll describe this in more detail as I have now put it on CodePlex.
As my previous team wasnt into traditional mock objects, we used this quite successfully for both Biztalk consumers and non Biztalk consumers. If you are not dealing with Biztalk , and if you have control over the consumer (especially if you are writing it from scratch), then i would recommend a mock object framework.