Skip to content

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:

Using SV Lab in JUnit/Maven tests to remove 3rd party dependencies

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");
    ...
}