Creating test data with WireMock
Testing end to end of complex systems is often complicated by stability problems. Testers are involved in the development process from the very beginning when a majority of endpoints are not yet implemented. Also for some reasons we might have a limited access to particular microservices.
In some edge cases there’s a need to test scenarios that are difficult to simulate. At that point usually system health check does not exist. Running tests on real environment results in random, nondeterministic result – created reports are worthless. There are several ways to deal with this kind of problems and build Selenium tests that are not so fragile. One of them is the usage of WireMock simulator.
Use case
Imagine a situation where we are testing an editing customer wallet in UI. First of all we need to find the existing customer (or create one in the ideal case) before calling the wallet service. Then create the wallet to be able to edit it. In order to avoid „keeping the state” every test case should create all required data at the beginning and remove them at the end. Thus, our BDD scenario should look like that:
- Given I create customer without a wallet
- And I create an empty wallet for the existing customer
- When I edit amount of wallet for the existing customer
- Then I verify that the wallet amount is updated
- And I remove the created wallet
- And I remove the created customer
For a real system let’s imagine the following situation: customer search endpoint is not stable and at the same time creating the customer is not implemented. Running such a scenario on our environment can be problematic for steps 1, 2, 5, 6 if the development is in progress or there are environment stability issues. For our scenario we should be focused on editing the existing wallet. Creating customer and wallet or removing them should be tested by other scenarios. Creation test data can be processed in several ways:
- with the use of WireMock
- manually
- direct SQL insert into database
- run Postman mock service
- run SoapUI mock service
- use application API endpoints if possible
- create Selenium UI test scenario
- mass copy from production with masking sensitive data
- using Nokogiri
- with the use of TestComplete
- with the use of GEDIS Studio
- JavaScript Mountebank
- Stubby4j
- Hoverfly
Manual creation is the easest one – it’s fast and therefore the most popular. Automatic test data creation requires additional investment and is time consuming. Hovewer, for crutial functionalities it’s worth working on such a solution – especially for complex systems profits outweigh the costs. Automatic regression run can be scheduled periodicaly (usually Jenkins job runs during the night to avoid generating traffic that could influence developers’ and testers’ work). The generated results report provides with information about the quality of the software product or the service under test.
WireMock implementation
This article is focused on WireMock as the way to create test data. Such tool runs simple HTTP server. It’s important to have it running locally in order to avoid network connection issues and provide robust resolution. Having that in mind let’s implement our steps with the use of WireMock to simulate responses of the customer and wallet services. The first step to work with WireMock is to add devendency to Maven project:
<dependency>
<groupid>com.github.tomakehurst</groupid>
<artifactid>wiremock-jre8</artifactid>
<version>2.27.2</version>
<scope>test</scope>
</dependency>
To initialize WireMock:
public WmStubber() {
private WireMock wm = new WireMock("https", "https://0.0.0.127/myApp/", 443);
}
Customer creation step implementations:
private WmStubber wmStubber = new WmStubber();
List<stubmapping> wmStubs = new ArrayList<>();
@Given("I create customer without a wallet")
public void setCustAsStub() {
wmStubs.add(wmStubber.setCustStub);
}
public StubMapping setCustStub() {
JSONParser jsonParser = new JSONParser();
JSONOnject custDetailsFile = (JSONObject) jsonParser.parse(new FileReader("custDetails.json"));
Gson gson = new GsonBuilder().serializeNulls().create();
Customer custDetailsStub = gson.fromJson(custDetailsFile.toString(), Customer.class);
custDetailsStub.setCustomer(custDetailsStub);
String jsonResponse = gson.toJson(custDetailsStub);
return wmStubs.register(put(urlEqualTo("/customer").atPriority(1)
.willReturn(aResponse().withBody(jsonResponse)
.withHeader("Content-Type", "application/json")
.withStatus(200)));
}
Where custDetailsStub class:
@Data
public class CustDetailsStub {
private Customer customer;
}
With such implementation customer data can be uploaded from a simple json file with fields according to Customer class, i.e.:
{
“customerDetails”: {
“firstName”: “Thomas”,
“lastName”: “Smith”,
“address”: {
“street”: “42th street”,
“number”: “4/2”,
“zip code”: “31-042”,
“city”: “New York”
}
}
}
This way we can implement step number 1 and 2 for creating wallet or any other resource we need. For removing data (step 5 and 6) it’s enough to run cleanMapping method:
wmStubber.cleanMapping(wmStub);
Conclusion
The presented code allows to enhance the stability of tests by stubbing data. However such tests often omit crucial changes of application, thus tests based on real data should be also periodically run. Above implementation simulates services’ mocked responses to resolve problem of creating data. Hovewer WireMock is powerful tool – can be also used to:
- test supporting timeouts
- discovering application changes by simulating constant response time
- verify downtime resistance of external services/applications
References
https://techblog.ing.pl/blog/stabilizacja-testow-z-wykorzystaniem-rozbudowanego-wiremocka
https://www.jcommerce.pl/jpro/artykuly/mockowanie-w-testach-nie-tylko-automatycznych