Simulating Services With SV Lab in JUnit Tests Run With Maven
Watch a video explaining how to leverage simulated REST services in JUnit tests run with Maven:
Service virtualization helps unit testing application components by resolving dependencies on back-end services. This topic describes how to simulate a REST service that is configured and launched from a JUnit test run with Maven.
The example application
We use the demo application that is available on GitHub.
The application being tested smartly controls an irrigation system. It conserves water consumption by reducing the amount of water used for irrigation according to the 24-hour precipitation forecast.
The goal of testing the application logic is to verify its behavior under conditions of rainy weather, when the irrigation should conserve water, as well as on a dry day when the irrigation amount should not be reduced.
There are two scenarios simulating different weather forecasts for each of the two tests:
@Test
public void testWaterSavingOnRainyDay() throws Exception {
sv.runSimulation("rainyDay");
...
}
@Test
public void testIrrigationOnDryDay() throws Exception {
sv.runSimulation("dryDay");
...
}
Integration testing
The JUnit test for the IrrigationLogic is accompanied by simulation models and virtual lab configuration. The test compiles model sources and deploys the virtual lab in the initialization phase. The WeatherClient is configured to use an HTTP proxy connector in virtual lab when communicating with the WeatherService, directing it to a virtual service. The virtual service responds according to the running scenario simulating desired conditions for each test case.
Application Model
The SmartIrrigationTest contains two test cases, each requiring a different
weather forecast to be simulated. This means that we have two scenarios in the application
model in src/main/resources/demo/SmartIrrigationApplicationModel.js
:
@sv.applicationScenario
rainyDay() {
this.weatherForecastServiceModel.rainyDayMeteogram();
}
@sv.applicationScenario
dryDay() {
this.weatherForecastServiceModel.dryDayMeteogram();
}
Service Model
The actual behavior of the weather forecast service is defined in the
src/main/resources/demo/WeatherForecastServiceModel.js
. The
WeatherClient performs two REST calls to obtain the current forecast. First it
gets the ID of the latest weather forecast run by the Czech Hydrometeorological
Institute's supercomputer:
this.service.GET("/apirun")
.withRequest()
.withResponse({
"id": "190515_12"
}, sv.JSON)
...
Then it fetches the actual forecast data in a second call:
this.service.GET("/apimeteogram")
.withRequest()
.withQueryParameters(sv.svVar({}))
.withResponse({
"data": {
"rain_dif": {
"max": 10.0,
"values": [
2.1297, 1.2324, 2.4592, 2.5837, 2.5626, 1.4771,
...
The real service at http://www.medard-online.cz returns a lot of forecast
information, but we kept our model simple by duplicating only the data actually
consumed by WeatherClient in our application - mainly the forecast run ID and the
rain_dif
precipitation forecast.
Virtual Lab
In order to run and use the simulation, we have to configure and start a virtual lab. The virtual lab can be configured using a JSON file, or it can be set up and controlled using the SV API.
In this example, we load the lab configuration from the
src/main/resources/sv-lab.json
file and compile the module from application
and service model sources (SmartIrrigationApplicationModel.js
and
WeatherForecastServiceModel.js
):
final String labConfigPath = "classpath:/sv-lab.json";
final String vslPath = "classpath:/demo/*";
sv.loadActiveVirtualLab(labConfigPath, sv.compileModuleFromSources(vslPath), true);
It is convenient to keep the VSL sources and sv-lab.json
file in the
resources
directory and access them with "classpath:/..."
Spring resource locators.
Alternatively, you can use relative ("file:target/test-classes/sv-lab.json"
) or
even absolute
("file:///c:/test/sv-demos/smart-irrigation-maven/target/test-classes/sv-lab.json"
) paths to
locate the files.
In the configuration file we define the virtual lab on which all the services will run and select the application model to use:
"virtualLab": [
{
"id": "virtual-lab:9001",
"displayName": "Smart Irrigation Test Virtual Lab",
"applicationModelId": "SmartIrrigationApplicationModel",
"connector": ...,
"virtualServiceInstance": ...
}
]
Then we create an HTTP proxy connector providing connectivity for the REST virtual service that we want to simulate.
"connector": [
{
"id": "connector",
"connectorType": "httpProxy",
"properties": {
"bindPort": 9001
}
}
]
Here we create a service instance specifying the service url through which it will be
exposed and selecting the SIMULATE_SERVICE
simulation mode.
"virtualServiceInstance": [
{
"virtualServiceId": "WeatherForecastServiceModel.RestServiceInterface",
"serviceMode": "SIMULATE_SERVICE",
"endpoints": [
{
"properties": {
"httpServiceUrl": "http://www.medard-online.cz"
},
"connectorId": "httpConnector"
}
]
}
]
We start the virtual lab:
sv.startActiveVirtualLab();
Now we are ready to simulate the chosen scenarios in each test method:
@Test
public void testWaterSavingOnRainyDay() throws Exception {
sv.runSimulation("rainyDay");
...
}
...
@Test
public void testWaterSavingOnDryDay() throws Exception {
sv.runSimulation("dryDay");
...
}