com.github.tomakehurst.wiremock.client.VerificationException: Expected at least one request matching

11.4k views Asked by At

I want to create a Stub for an API and want to verify API call and response returned by the server. for that i have implemented WireMock example :

import org.junit.Rule;
import org.junit.Test;

import com.github.tomakehurst.wiremock.junit.WireMockRule;

public class MockTestDemo {

    private static final int WIREMOCK_PORT = 8080;

    @Rule
    public WireMockRule wireMockRule = new WireMockRule(WIREMOCK_PORT);

    @Test
    public void exampleTest() {

    stubFor(get(urlEqualTo("/login")).withHeader("Accept", equalTo("application/json"))
            .willReturn(aResponse().withStatus(200).withBody("Login Success")
                    .withStatusMessage("Everything was just fine!"))
            .willReturn(okJson("{ \"message\": \"Hello\" }")));

       verify(getRequestedFor(urlPathEqualTo("http://localhost:8080/login")) 
            .withHeader("Content-Type",equalTo("application/json")));       }

}

But getting below error :

com.github.tomakehurst.wiremock.client.VerificationException: Expected at least one request matching: {
  "urlPath" : "localhosturl/login",

   "method" : "GET",

  "headers" : {
    "Content-Type" : {
      "equalTo" : "application/json"
    }
  }
}

Requests received: [ ]
  at com.github.tomakehurst.wiremock.client.WireMock.verificationExceptionForNearMisses(WireMock.java:545)
  at com.github.tomakehurst.wiremock.client.WireMock.verifyThat(WireMock.java:532)
  at com.github.tomakehurst.wiremock.client.WireMock.verifyThat(WireMock.java:511)
  at com.github.tomakehurst.wiremock.client.WireMock.verify(WireMock.java:549)
  at com.wiremock.test.MockTestDemo.exampleTest(MockTestDemo.java:23)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
  at java.lang.reflect.Method.invoke(Unknown Source)
  at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
  at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
  at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
  at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
  at com.github.tomakehurst.wiremock.junit.WireMockRule$1.evaluate(WireMockRule.java:73)
  at org.junit.rules.RunRules.evaluate(RunRules.java:20)
  at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
  at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
  at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
  at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
  at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
  at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
  at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

If I comment verify part then test executed successfully also i have verified the same using postman by calling http://localhost:8080/login and it returning response successfully ?

Is any thing I'm missing here ?

2

There are 2 answers

1
D.Salter On BEST ANSWER

In your code you are stubbing out a response and then verifying that a request has been made for that stub. You are not however making a call to the endpoint and so the test is failing.

You need to invoke the endpoint before verifying that it is called.

If you use Apache Commons HttpClient, you could write your test as:

@Test
public void exampleTest() throws Exception {

    stubFor(get(urlEqualTo("/login")).withHeader("Accept", equalTo("application/json"))
            .willReturn(aResponse().withStatus(200).withBody("Login Success")
                    .withStatusMessage("Everything was just fine!"))
            .willReturn(okJson("{ \"message\": \"Hello\" }")));

    String url = "http://localhost:8080/login";
    HttpClient client = HttpClientBuilder.create().build();
    HttpGet request = new HttpGet(url);
    request.addHeader("Content-Type", "application/json");
    request.addHeader("Accept", "application/json");
    HttpResponse response = client.execute(request);

    verify(getRequestedFor(urlPathEqualTo("/login"))
            .withHeader("Content-Type", equalTo("application/json")));
}
0
Felix Aballi On

Kindly, recommend using a class rule annotation/field (@ClassRule) for JUnit 4 (in those cases, where config could be reused on multiple unit tests).

@Rule could cause unexpected behaviors on async or http requests contexts, when stubs aren't registered yet.

Versions: 2.21.0 -> ... -> 2.31.0.

Note: In my particular case, had multiple tests reusing config and all the requests where executed correctly (debugging & checking mocked responses deserialized onto in-memory DTOs).

Then:

// ... WIREMOCK_PORT

@ClassRule
public static final WireMockClassRule WIRE_MOCK_RULE = new WireMockClassRule(WIREMOCK_PORT);  // public

Also, recommend verifying mocked request was made to WireMock registered stubs.

Steps:

  1. Create stub: WIRE_MOCK_RULE.stubFor(get(urlPathMatching(...))) // get, post, ...
  2. Hit mocked endpoint with a Http client
  3. Verify stub was invoked: verify(getRequestedFor(urlPathMatching(...)))
//{get, post, ...}RequestedFor(...) API methods for a particular HTTP request

verify(getRequestedFor(urlPathMatching("a-url-pattern"))); //urlEqualTo, ...