Mocking or faking a SOAP web service in .Net
A few days ago I came up against a problem with a 3rd party SOAP web service we’re consuming from an ASP.Net website. It’s one of those special SOAP web services that has about 100 methods, each of which has the same signature: takes one argument, a string, and returns a string. The problem is that those strings are huge bloody great XML documents, which have to validate against several different XSD schema’s each.
Not being particularly savy with “Enterprise grade” XML, I was causing the 3rd party’s development server to choke on my data and vomit up a nice exception. Whenever I asked for help, I was politely told that my XML didn’t validate, and to bugger off and stop abusing their poor server until it did. So I wanted to write tests which assert that the XML submitted to any particular method should validate against the relevant XSD schema(s). Only once that test passed would I dare to submit anything to the development service.
A little about our architecture:
We have a facade class which hides the crazy / wraps the service. Amongst other things it builds the XML, submits it to the service, and parses the results. I wanted to test my facade, by mocking out the actual web service bit to both capture the XML that was submitted (so I could validate it) and also stop me from having to wait 30 seconds for a response to wind it’s way back across the intertubes from the 3rd party.
“Easy” thinks I, “code to a contract, not an implementation, and use dependency injection to pass the web service proxy into the Facade”. On live and in my integration tests I can pass in the real thing, and in my fast facade tests (or any other time it suits me) I can pull the old switcheroo and pass in a fake (or a mock, or a spy…)
Herin lies the rub…
Being a bit Old school, I’d consumed the service by using WSDL.exe, which knocks you up a C# class containing a proxy for the webservice. You can then merrily call this proxy like any other class with out having to lick so much as a single SOAP envelope. The problem I had was how to swap it out for something else. How do I “code to a contract not an implementation” when the only implementation I have was written by a tool (snigger) and is decidedly concrete?
1st thought, does it implement any kind of interface?
No. Didn’t I just say that?
2nd thought, can I inherit from it to create my mock/fake/stub/whatchamacallit, and override the methods under test to capture the XML?
Sort of - but not nicely. The problem is the class is marked “internal”. Both my facade and the proxy live in the same business project (and hence assembly). This was fine when the only class that had any references to the proxy was the facade. But now I want to inject the damned things from all over the shop, and inherit from them in test projects and the like. All my Fakes, stubs and mocks would have to live in the same assembly as the proxy. Not wanting to pollute the business project with test code, I vetoed that option.
I could have manually edited the class to make it, and all it’s methods, public. However editing classes generated by a tool is not a clever idea. Firstly it would be really boring and take ages (ctrl-h), secondly two years from now when the web service changes ever so slightly, some poor sap (probably me) is going to naively regenerate the class, and cause about a thousand compiler errors. After sobbing into my coffee and checking the comments in the version logs, the afore mentioned sap will figure out why and then spend a mind numbing afternoon re-editing the automatically generated class. Again. (ctrl-h)
3rd thought - can I get WSDL.exe to generate interfaces for me?
I didn’t know, and google didn’t tell me after a cursory glance, So I asked on stack overflow. The answer is… nearly. WSDL.exe has an optional switch, /si which generates an interface instead of a proxy class. Unfortunately that’s all it generates and there’s no way to make it generate proxy classes which implement that interface. The idea seems to be that if you’re given a WSDL of a service you want to implement, rather than consume, you can get Visual Studio (or resharper) to stub out the generated interface, then just decorate it with [WebMethod] attributes and you’re away. Which leads one to ask…
4th thought - could you implement your mock as a web service, and merely change the URI to point your proxy at that instead of the 3rd party?
No. (but yes in theory). The idea is to write fast tests to validate some XML. I don’t want that to involve http, not to mention that the mock service would have to run somewhere (Cassini presumably) and I guess would therefore be in a different process to the tests which invoked it, making it a bugger to extract the XML back into the test to assert that it validates. There are even third party programs which will mock a web service based on it’s WSDL (http://www.soapui.org/Getting-Started/mock-services.html), but I still don’t think these belong in a fast test. Anyway, It’s the Facade I want to test, not the SOAP service or proxy classes. The facade barely knows anything about the service, and certainly doesn’t depend on the fact that the interwebs are carrying it’s calls across the ether and back again.
Prompted by the answers on stack overflow, I realised I could create a class that inherited from the concrete proxy class /and/ the interface. The inherited concrete methods provide an implicit implementation of the interface. Awesome! I can now write my code against the interface, and use this little beastie to cast my concrete classes to said interface.
That’s the Adaptor pattern isn’t it?
The only problem is that the concrete class is still “internal”, which has two consequences. First, my adaptor has to live in the same project/assembly as the proxy class. Well that’s fine, that’s where it belongs anyway. The big problem is that a derived class can not be declared with laxer (more public) access modifiers than it’s base class. In other words my Adaptor has to be marked Internal too. That was a bit of a pain, as I wanted to be using this thing in another set of tests, my integration tests. I solved that problem by building a little factory class that news up an instance of the adaptor, but returns it as an instance of the interface. As a neat side effect it’s also the nicest place to worry about the URI of the web service when newing up the proxy class.
Now that my Facade was coded to an interface, it was the work of but a moment to get resharper to stub out another class in my test project to fake the web service (I’m sure it would have been just as easy to use moq or something). I’m still not sure if my new test class is a mock a fake or a spy. It captures the submitted string argument (our XML) and saves it safely in a property (called SuperSecretSpyXmlArgumentOfDoom or something). It then promptly loses the will to live and throws a NotImplementedException. (it probably shouldn’t do that, but it saves the fake from needing to return valid XML, which the facade would attempt to parse). The test catches and ignores the exception, and can extract the XML from the fake and validate it against the XML schema.
My XML has now been XSD certified as all natural and 100% organic, thus proving that the 3rd party web service must have been vomiting up exceptions because it’s a sickly, weak and feeble, excuse of a web service.
Eat that 3rd party web service.