Tuesday, 17 May 2016

Service Virtualization and Given/When/Then

I recently found that I had problems explaining how service virtualization or over-the-wire stubbing (however you wanna call it) fits into the usual type of testing I do on a daily basis and what I mean when I say “service virtualization”. Here is a brief explanation of how that could work for developers and QAs.

Given/When/Then testing

In almost all cases when I create software these days I will have some level of automated testing. How much coverage I have depends on the context, but I almost always have a minimal amount of automated tests.

When I write the automated tests I split them into 3 logical sections. Let us imagine I am writing a simple application that talks to Markit market data APIs to fetch stock quotes and display the last price to the user.

The “given’s” section is where I set up the system and its dependencies. In this section I will make calls to over-the-wire stubs (or virtual services) to set them up for the test. For example, the test will call a Wiremock instance running in a separate process and set it up so that when the application asks for a stock quote, Wiremock will pretend to be the Markit market data API and return a canned response.

The “when’s” section is where we exercise the system under test.

The “then’s” section is where we make assertion on the state or interactions,

For example in Java with JUnit it would look like this:
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.wbsoftwareconsutlancy.FinanceApplication;
import org.apache.http.client.fluent.Content;
import org.apache.http.client.fluent.Request;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static junit.framework.TestCase.assertEquals;

public class FinanceApplicationTest {
    @Rule
    public WireMockRule forecastIoService = new WireMockRule();

    private FinanceApplication financeApplication = new FinanceApplication();

    @Before
    public void setUp() throws Exception {
        financeApplication.start();
    }

    @After
    public void tearDown() throws Exception {
        financeApplication.stop();
    }

    @Test
    public void parsesLastPriceFromStockQuote() throws Exception {
        forecastIoService.stubFor(get(urlEqualTo("/MODApis/Api/v2/Quote/json?symbol=AAPL"))
                .willReturn(aResponse().withBody("{\"Status\":\"SUCCESS\",\"Name\":\"Apple Inc\",\"Symbol\":\"AAPL\",\"LastPrice\":103.17}")));

        Content content = Request.Get("http://localhost:" + financeApplication.port + "/stock-quote-last-price")
                .execute()
                .returnContent();

        assertEquals("103.17", content.toString());
    }
}
 

Service Virtualization

The given/when/then framework has proven to be working very well when I was working on a greenfield project or working on a system that has been designed with testability in mind. It might be a challenge to follow this pattern if you are working with a legacy codebase that has not been designed with testability in mind. You might have to introduce a more complex, stateful over-the-wire stub (virtual service) or even implement a simulation.

When the system or module I am working on has not been designed with testability in mind, I find myself tackling this complexity by adding more complexity to the testing infrastructure. For example, in order to implement an automated suite of tests, I need to introduce a complex virtual service (stub). Introducing more complexity to tackle existing complexity is a slippery road. There are times where it is a good tradeoff. Unfortunately, most cases I have seen it being done it was a good short term solution that has turned into a high maintenance cost long term one.

So what do I do?
So, what are the actions for you today? Find a few complex virtual services you have created that require a lot of your time for maintenance. Understand how much time/effort/money goes into maintaining them. Speak to developers and architects and understand if it is a good idea to keep on maintaining them, or would it be a good idea to refactor selected system under test modules to make them more testable and reduce the overall system under test maintenance costs by getting rid of complex virtual services.