JVM Self Initializing Fake

Self Initializing Fake library for the JVM (inspired by https://martinfowler.com/bliki/SelfInitializingFake.html)

License

License

Categories

Categories

Axon Application Layer Libs Distributed Applications
GroupId

GroupId

com.maxondev.jsif
ArtifactId

ArtifactId

jsif
Last Version

Last Version

0.1.3
Release Date

Release Date

Type

Type

jar
Description

Description

JVM Self Initializing Fake
Self Initializing Fake library for the JVM (inspired by https://martinfowler.com/bliki/SelfInitializingFake.html)
Project URL

Project URL

https://github.com/maximn/jsif
Source Code Management

Source Code Management

https://github.com/maximn/jsif.git

Download jsif

How to add to project

<!-- https://jarcasting.com/artifacts/com.maxondev.jsif/jsif/ -->
<dependency>
    <groupId>com.maxondev.jsif</groupId>
    <artifactId>jsif</artifactId>
    <version>0.1.3</version>
</dependency>
// https://jarcasting.com/artifacts/com.maxondev.jsif/jsif/
implementation 'com.maxondev.jsif:jsif:0.1.3'
// https://jarcasting.com/artifacts/com.maxondev.jsif/jsif/
implementation ("com.maxondev.jsif:jsif:0.1.3")
'com.maxondev.jsif:jsif:jar:0.1.3'
<dependency org="com.maxondev.jsif" name="jsif" rev="0.1.3">
  <artifact name="jsif" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.maxondev.jsif', module='jsif', version='0.1.3')
)
libraryDependencies += "com.maxondev.jsif" % "jsif" % "0.1.3"
[com.maxondev.jsif/jsif "0.1.3"]

Dependencies

compile (1)

Group / Artifact Type Version
com.github.tomakehurst : wiremock jar 2.12.0

test (4)

Group / Artifact Type Version
org.apache.httpcomponents : httpclient jar 4.5.4
org.apache.httpcomponents : fluent-hc jar 4.5.4
org.slf4j : slf4j-simple jar 1.7.25
junit : junit jar 4.12

Project Modules

There are no modules declared in this project.

Build Status

jsif

Self Initializing Fake library for the JVM (inspired by https://martinfowler.com/bliki/SelfInitializingFake.html)

What does it do?

It creates a self initialized fake based on a communication with a real server.
On the first time that you run it, it runs in a Recording mode, means that it proxies the communication to a real server and at the same time saves the communication in to a file.
On consecutive runs it'll start up in a Playback mode, means that it loads the data from the recorded run and behaves like the real server.

Let's see a real life example, we have this very basic Weather class that communicates with an external Weather service (https://www.metaweather.com/). This class should have Integration Test to make sure that it functions correctly.

Weather.java

package com.maxondev.sample.app;

import org.apache.http.client.fluent.Request;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

public class Weather {

    private final String baseUrl;

    public Weather(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    public String forCity(String city) throws IOException {
        String encodedCity = URLEncoder.encode(city, StandardCharsets.UTF_8.name());
        return Request
                .Get(baseUrl + "/api/location/search/?query=" + encodedCity)
                .execute()
                .returnContent()
                .asString();
    }
}

That's how the test will look With jsif (Java SelfInitializingFake)

WeatherIT.java

package com.maxondev.sample.app;

import com.maxondev.jsif.SelfInitializedFake;
import org.hamcrest.CoreMatchers;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.IOException;

public class WeatherIT {
    private static final int fakePort = 8087;
    private static final SelfInitializedFake fake =
            SelfInitializedFake
                    .builder()
                    .proxyTo("https://www.metaweather.com")
                    .recordTo("weather_recordings")
                    .listenOnPort(fakePort)
                    .asAutoMode();

    @BeforeClass
    public static void setUpBeforeClass() {
        fake.start();
    }

    @AfterClass
    public static void tearDownAfterClass() {
        fake.stop();
    }

    @Test
    public void forCity_success() throws IOException {
        Weather weather = new Weather("http://localhost:" + fakePort);

        String res = weather.forCity("london");

        Assert.assertThat(res, CoreMatchers.containsString("\"latt_long\":\"51.506321,-0.12714\""));
    }

    @Test
    public void forCity_wrongCity_emptyResult() throws IOException {
        Weather weather = new Weather("http://localhost:" + fakePort);

        String res = weather.forCity("london");

        Assert.assertThat(res, CoreMatchers.containsString("\"latt_long\":\"51.506321,-0.12714\""));
    }
}

How does it work?

When running for the first time, you'll see in the log
[main] INFO com.maxondev.jsif.SelfInitializedFake - Starting in `Record` mode
And the Fake will initialize itself - It'll proxy the communication to the real external server and record it. The communication will be persisted in into a json file (under test/resources/weather_recordings)

The next time that you'll run it, you'll see in the log
[main] INFO com.maxondev.jsif.SelfInitializedFake - Starting in `Play` mode
The Fake will run in Play mode now and it'll interact in the same way, but this time instead of proxying the traffic to the real server it'll use the persisted communication from the first run.

Under the hood?

This library uses WireMock library (http://wiremock.org/) for the recording & playback.
It wraps WireMock and allows an easy Self Initializing Fake.

Versions

Version
0.1.3
0.1.2
0.1.0