While doing some integration testing for BizTalk hosted WCF services I met a few challenges that required some creative thinking if I wanted to do things the right way… As a quick intro I was making use of BizUnit 4.0 to execute my tests and making use of the WCF test step to call on my WCF service, executing my tests from Visual Studio 2012 against a local BizTalk 2013 environment. This was a one way WCF service making use of the WSHttp binding with transport security and basic authentication, also making use of a WCF service behaviour to perform authorization ensuring that the user in question belongs to a specified active directory group. At this stage I was only going to be executing the tests against my local VM however at some point in the future I would want to run these tests on actual test environments.
Challenge number one was that since my WCF service made use of transport security I couldn’t have my test project’s app.config reference an endpoint URL like https://localhost/…. since this wouldn’t match up with the self signed security certificate that I had bound to the HTTPS port in IIS. I would instead need to put the fully qualified name of my VM which matches up with the certificate bound to the HTTPS port in my app.config. This isn’t all that acceptable given that it isn’t necessarily going to be my PC on which the integration tests are next executed on, given that it could be any other developer working on them in the future. I would ideally also like to be able to have my integration tests run against staging or UAT environments in the future, and would like to repoint my tests to these environments without making any changes to any code in source control including my app.config or adding new environment specific tests. I decided that I wanted for the URL to be overridden by replacing a placeholder value in the URL in my app.config with one read in from an SSO application.
Challenge number two was that since my service made use of basic authentication and active directory group based authorization I had to be able to dynamically choose which credentials I was going to make use of when I called the service given that the credentials required to perform the same test on each environment would be different. Being a very thorough (some might have ruder words for me but I will keep this blog post PG) tester I wanted to also be able to perform negative testing whereby I had credentials that did not authenticate or credentials that did authenticate but weren’t authorized to call the service and I didn’t want any of these credentials hardcoded in my app.config or code or the resolution of the credentials to result in me having to modify the WCF test step. Once again I decided that I was going to make use of an SSO application to lookup the credentials that I wanted to use when I called on the service.
In order to do this I decided to implement a WCF endpoint behaviour which will implement the out of the box ClientVia behaviour which allows for the overriding of an endpoint URL and a ClientCredentials behaviour to set the relevant credentials. Now I could have made use of the ClientVia or ClientCredentials behaviors directly in my app.config however that breaks my principle that I don’t want to update the source controlled app.config. I could have also made a custom implementation of the BizUnit WCF test step which dynamically looks up the URL and credentials I want to use and which then programmatically implements the ClientVia and ClientCredentials behaviors with the resolved values, however that went against my principle of not updating the WCF test step which performs a very generic function very well.
I created a new WCF endpoint behavior and implemented the below ApplyClientBehavior method to make use of the out of the box behaviors with values resolved from an SSO config store (this could of course be split into two discrete WCF behaviors but for the purpose of this blog post I decided to treat them as one).
Note in the above that the _SSOApplication variable is actually a parameter for the behavior’s constructor so it can be set within the app.config allowing the behaviour to be reused across different projects. The same applies for the keyPrefix variable which is used to specify which set of credentials are being looked up, allowing for the SSO store to contain multiple sets of credentials. The SSO application would look like the below.
In order to make use of these behaviors the test projects app.config would have to be adjusted so that it looks like the below.
Note the highlighted sections in the above screenshot and my notes below explaining what they do.
- The first highlighted section shows the registration of the behaviour extension and linking it with a local friendly name. Note that the type includes the fully qualified behaviour extension element class name and the fully qualified assembly name (you can get this using the “gacutil -l” command). This allows for us to use the behavior in our app.config.
- The second section is where we register a behavior configuration with a friendly name and specify which behaviors it implements and with what configuration. In the above screenshot I registered two behavior configurations one which specifies a keyPrefix value of Johann and one which specifies AITM, both specifying an SSO application name of Testing.
- The third section is adjusting the client endpoint registration such that they implement one of our registered behavior configurations. We also adjust the endpoint name so that it is obvious which behavior configuration they implement. Also note that the URLs have the word placeholder in them where we want to override the URL with the value fetched from the SSO config store.
Now when we actually create our BizUnit test step we need to ensure that we specify the endpoint name which matches the client endpoint in our app.config that implements the behavior that we want to implement for our test. In the below screenshot the WCF test step specifies an endpoint name of MathJohannCredentials which means that the Johann username and password from the SSO config store will be used as credentials when calling the service, and that the https://placeholder/MathsService/Maths.svc url will be overridden with https://jc-bt2013vm.aitm.co.nz/MathsService/Maths.svc. Making use of the AITM credentials would be as simple a task as implementing a similar test that specifies an endpoint name of MathAITMCredentials.
These are of course just examples of how you can use WCF behaviors to enable you to write flexible integration tests. You could very easily use this concept to lookup values from other config stores such as a database, the business rules engine, or a configuration file, or perhaps to override other WCF behaviors. If anyone has any other good ideas on how WCF behaviors could be used to make testing more flexible then please do add a comment to this post.