At work last month, I was assigned to fix some bugs in an asynchronous legacy code base. My supervisor gave me a month to see what I could do, and to see if I could fix a few tricky bugs. The code is divided into two sections, a client application and a web server. Both the client application and the server have their own persistence, and they communicate through a soap web service.
I wanted to try and write some sort of end-to-end tests around this, but I could not figure out how to get around that web service. I don't want my tests to rely on a server having to always be up, so I initially was planning on writing tests from the client database to the web service, where I would just stub some responses. I got about an hour into that plan, before I realized I would then have to do that same thing on the server, and that sort of testing will not really tell me what the code does. I needed to cover this whole process end-to-end.
I walked around for a bit, thinking. Then it hit me, both the server and client code are written in VB.NET, and, except for the web service, work just like plain old highly-coupled code. Hmmm.
For the first pass, I wrote an interface to wrap the web service, then used dependency injection to inject a fake web service that (and here is the cool part) simply calls around the web service entirely to the server code directly and injects a different database connection string, so the server talks to a second database I have prepared.
Just like that, I can run, all on my machine, 99 percent of the code in a single end-to-end test. I can even setup several client databases, and rotate them out, to "swap" between several clients in the middle of the tests.
I added a few "integration" tests that do talk to a real published testing web service, just to make sure everything is still in place correctly.
Now, I said this was asynchronous, and it is, the executed system-under-test kicks off a thread to talk to the web service, and so to get it to test, I needed to wait for the thread to finish, then do my assertions.
I used a system where the spun off thread will set a boolean when it has finished running, to let the main thread know it has finished, and the main thread just keeps checking that boolean until it is true. While hackish, that is my current working solution, as no more then one thread is ever spun off at a time, I can just have my test wait for the thread to finish, then complete the required assertions.