DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • User-Friendly API Publishing and Testing With Retrofit
  • From APIs to Event-Driven Systems: Modern Java Backend Design
  • Jakarta EE Glossary: The Terms Every Java Engineer Should Actually Understand
  • Translating OData Queries to MongoDB in Java With Jamolingo

Trending

  • Mocking Kafka for Local Spring Development
  • Ingesting Fixed-Width Mainframe Files Into Delta Lake: The Details Nobody Writes Down
  • Rethinking Java CRUDs With Event Sourcing and CQRS Patterns
  • Lambda-Driven API Design: Building Composable Node.js Endpoints With Functional Primitives
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. WireMock With Dynamic Proxies

WireMock With Dynamic Proxies

This quick lesson in WireMock considers using dynamic proxies with your tests. We'll use the OpenWeather API in this example.

By 
Upender Chinthala user avatar
Upender Chinthala
·
Feb. 06, 18 · Tutorial
Likes (5)
Comment
Save
Tweet
Share
19.7K Views

Join the DZone community and get the full member experience.

Join For Free

In this series, let's learn about the WireMock dynamic proxy. We will also see how to switch mocks real service requests. For more information on learning WireMock, visit this link.

In this example, I used the OpenWeather API to get weather information. Click here for more details.

WireMock has a feature where you can extend it by using its extensions such as Transformer and PostServeAction.

Transformers(ResponseDefinitionTransformer): This extension mechanism makes it possible to dynamically modify responses, allowing header re-writing and templated responses, amongst other things.

Image title

In the above diagram, Service sends the request to WireMock, then WireMock executes one of its extensions, i.e the ResponseDefinitionTransformer#transform method. We have a simple validation inside the transform(override by the subclass) method — i.e if the OpenWeather API service is available or not. If the API service is available, then we attach it to the proxy URL and return a new ResponseDefinition. WireMock sends the request to the OpenWeather API service and receives the response. Otherwise, I set my own mock response to the body and return ResponseDefinition. Let us see the FailOverTransformer code:

package com.mim.poc;

import java.net.MalformedURLException;
import java.net.URL;
import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.extension.ResponseDefinitionTransformer;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.http.ResponseDefinition;

public class FailOverTransformer extends ResponseDefinitionTransformer {

    public static final String FAIL_OVER_TRANSFORMER = "fail-over-transformer";
    public static final String WEATHER_PROXY_URL = "weather-proxy-url";
    public static final String WEATHER_MOCK_RES_BODY = "weather-mock-res-body";
    @Override
    public String getName() {
        return FAIL_OVER_TRANSFORMER;
    }
    @Override
    public ResponseDefinition transform(Request request, ResponseDefinition responseDefinition, FileSource files,
        Parameters parameters) {
        String proxyURl = parameters.getString(WEATHER_PROXY_URL);
        boolean found = false;
        try {
            found = HttpPingTestUtil.doesURLExist(new URL(proxyURl + request.getUrl()));
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return found ? ResponseDefinitionBuilder
            .like(responseDefinition)
            .proxiedFrom(proxyURl)
            .build() :
            new ResponseDefinitionBuilder()
            .withStatus(200)
            .withHeader("Content-Type", "text/plain")
            .withBody(parameters.getString(WEATHER_MOCK_RES_BODY))
            .build();
    }

}


  • Line 24: proxy URL is a setting in the WeatherIT class Looking at line 23, the proxy URL is coming from a properties file,
  • Line 27: The HttPingTestUtil class has the doesURLExist method to validate whether the service is available or not. See the complete code in the GitHub repo. If the service is available, then it returns true; otherwise false.
  • Line 31: If found=true, then ResponseDefinition attaches to the proxy URL and returns the new ResponseDefinition. Otherwise, it returns with a mock response body. The mock response body is set on WeatherIT.java Line 24: .withTransformerParameter(FailOverTransformer.WEATHER_MOCK_RES_BODY, readContentBy("/mock/mockresponse.xml"))));

Our integration test in Spring:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application-test.xml")
public class WeatherInfoIT {

    @Autowired
    private WeatherGateway gateway;

    @Value("${weather.proxy.url}")
    private String weatherProxyUrl;

    @SuppressWarnings("static-access")
    @Rule
    public WireMockRule openWeatherMockRule = new WireMockRule(wireMockConfig().options().port(8999)
        .extensions(new FailOverTransformer()));

    @Before
    public void init() throws Exception {
        openWeatherMockRule.stubFor(WireMock.get(WireMock.urlPathMatching(".*"))
            .withQueryParam("appid", WireMock.equalTo("b6907d289e10d714a6e88b30761fae22"))
            .withQueryParam("mode", WireMock.equalTo("xml"))
            .withQueryParam("q", WireMock.equalTo("London"))
            .willReturn(WireMock.aResponse().withTransformers(FailOverTransformer.FAIL_OVER_TRANSFORMER)
                .withTransformerParameter(FailOverTransformer.WEATHER_PROXY_URL, weatherProxyUrl)
                .withTransformerParameter(FailOverTransformer.WEATHER_MOCK_RES_BODY,
                    readContentBy("/mock/mockresponse.xml"))));
    }
    private String readContentBy(String filePath) {
        String contents = "";
        Resource resource = new ClassPathResource(filePath);
        try {
            contents = new String(Files.readAllBytes(resource.getFile().toPath()));
        } catch (IOException e) {}
        return contents;
    }
    @Test
    public void getInfo() {
        QueryParameters parameters = new QueryParameters();
        parameters.setAppId("b6907d289e10d714a6e88b30761fae22");
        parameters.setMode("xml");
        parameters.setCity("London");
        String response = gateway.send(parameters);
        System.out.println(response);
        //fake test
        Assert.assertTrue(true);
    }
}


  • Above WeatherIT.java On-Line 14: adding FailoverTransformer to WireMock extension
  • On-Line 22: registering FailoverTransformer with the name. see FailOverTransformer#FAIL_OVER_TRANSFORMER
  • On-Line 23: setting proxy URL as Transformer parameter
  • On-Line 24: setting Mock Response body as Transformer parameter

Finally, we run it as a JUnit getInfo() method. You will see the actual OpenWeather API response because the service is available — so WireMock hit the proxy.

Sample output:

Image title

Let's change proxy URL in the properties file and re-run JUnit getInfo():

weather.proxy.url=http://samples.openweathermap.or


Make sure we need to give the wrong URL, then the Mock response will return:

Image title


#wiremock endpoint
weather.endpoint.url=http://localhost:8999/data/2.5/weather?{city}&{mode}&{appid}
#real endpoint
#if you want switch to mock just change to incorrect address so that it failover to mock
weather.proxy.url=http://samples.openweathermap.org


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xmlns:task="http://www.springframework.org/schema/task" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd 
    http://www.springframework.org/schema/integration/jdbc 
    http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd
    http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd
    http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
       <context:property-placeholder location="classpath:application-test.properties" />

   <int:channel id="weatherInboundChannel" >
   <int:queue capacity="100"/>
   </int:channel>

       <int:channel id="weatherOutboundChannel">
       <int:queue capacity="100"/>
       </int:channel>

       <int:poller max-messages-per-poll="10" fixed-rate="500"  default="true"/>

       <int:gateway service-interface="com.mim.poc.WeatherGateway"id="weatherGateway" default-request-channel="weatherInboundChannel"  default-reply-channel="weatherOutboundChannel"/>

<int-http:outbound-gateway url="${weather.endpoint.url}" request-channel="weatherInboundChannel" reply-channel="weatherOutboundChannel"
http-method="GET" extract-request-payload="true" expected-response-type="java.lang.String">
<int-http:uri-variable name="city" expression="'q='+payload['city']"/>
<int-http:uri-variable name="mode" expression="'mode='+payload['mode']" />
<int-http:uri-variable name="appid" expression="'appid='+payload['appId']" />
</int-http:outbound-gateway>


</beans>


See the complete code in GitHub.

API integration test Java (programming language)

Opinions expressed by DZone contributors are their own.

Related

  • User-Friendly API Publishing and Testing With Retrofit
  • From APIs to Event-Driven Systems: Modern Java Backend Design
  • Jakarta EE Glossary: The Terms Every Java Engineer Should Actually Understand
  • Translating OData Queries to MongoDB in Java With Jamolingo

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook