Test-Driven Implementation of a SOAP Client in Rails

For a project I’m working on at the moment I need to allow the visitor to enter address details, one of the improvements to a regular form is the inclusion of post-code lookups—allowing the user to enter just a post code and have the rest of the address auto-filled.

Similar to the US, the UK uses a system of postal codes (for example, W14 9AA). And although the Royal Mail (and others) do provide data services, supporting a database of all 27 million addresses would be a little far-reaching for my project. So, I’ll re-use a web-service provided by a 3rd party (PostcodeAnywhere)—and in doing so take advantage of their superior hardware and uptime etc.

They charge for their service, and although I don’t mind paying for walkthroughs, it would end up a little expensive if for every test suite run I incurred multiple credit charges.

So, another time when mocks run to the rescue! The key advantages to doing so are:

1. Design. It’s nice being able to specify the design of our code—one of the key benefits of mocking and test-driven development. Doing so means we’re not tied to anybody else’s API, we can do things our way!
1. Cost. It’s not plausible (nor feasible) to incur a charge everytime we run our tests—it would just make us want to run them less often.
2. Stability & Determinism. We don’t want to write a test that depends on particular data being returned from the service. Updates may change this, so, instead we’ll write the majority of our tests with well-known, stable, deterministic data.
3. Speed. Web-service lookups will be slow. Not a big problem for visitors to the site, but for our tests, not good.
4. Ability to work without an internet connection. Although I am lucky to have a shiny 24megabit connection, there are times when I may not.

Firstly, we want a test for what we’re trying to get out of our address form:

def test_can_see_postcodes  test_here  assert_tag 2 children, options for our postcodesend

Now to implement it. We’ll decouple our lookup from our controller (single-responsibility an’ all that) and have a PostcodeLookup class that lets us search for addresses. So firstly, let’s start writing a test for it.

def test_can_find_addresses_for_postcode  PostcodeLookup.find_addresses("test")end

That won’t pass just yet, so let’s put in our mock PostcodeLookup implementation, with just enough to pass the test.

Now, in our fictional land, we’ll say that the postal code “test” actually has 3 potential addresses. So let’s test that…

def testend

Finally, we want it so we can retrieve a fully populated Address when we select one of the addresses we pull back, so let’s write a test that we can do that.

def test_can_retrieve_one_address    AddressLookup.get_address(selected)  assert_equal "Line 1", address.line_1end

Excellent. Let’s go back to our functional test and run it again, success!

All we have to do now is write an implementation that supports our actual web-service. For the time-being, let’s remove our mock and put in an actual implementation in our model.

Finally we have it all working so we can put our mock back into our testing folder—and we have a fully tested postcode lookup.