Search code examples
javaunit-testinggroovyokhttpspock

Writing Unit Test of Interceptors


I am working on a project where I need to write an interceptor which basically modifies headers. Below is a similar code

class AuthRequestInterceptor implements Interceptor {
  @Override public Response intercept(Interceptor.Chain chain) throws IOException {
        Request original = chain.request();

        // Request customization: add request headers
        Request.Builder requestBuilder = original.newBuilder()
                .header("Authorization", "auth-value"); 
    
        Request request = requestBuilder.build();
        return chain.proceed(request);
  }
}

I want to test if Authorization has been added to the request header by the interceptor. Here is the code for testing

class AuthRequestInterceptorTest extends Specification {
    AuthRequestInterceptor authRequestInterceptor = new AuthRequestInterceptor();
    OkHttpClient okHttpClient = new OkHttpClient();

    void setup() {
        try {
            okHttpClient = new OkHttpClient()
                .newBuilder()
                .addInterceptor(authRequestInterceptor)
                .build();
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            throw new WebClientException(e)
        }
    }


    def "Get Authorization in to header"() {

        given:
        HashMap<String, String> headers = new HashMap<>()

        when:
        Request mockRequest = new Request.Builder()
            .url("http://1.1.1.1/heath-check")
            .headers(Headers.of(headers))
            .build()

       Response res = okHttpClient.newCall(mockRequest).execute()

        then:
        res.headers("Authorization")
    }
}

The test is failing so I debugged the Response returned by AuthRequestInterceptor and it is as below

Response{protocol=h2, code=200, message=, url=https://1.1.1.1/}

I want to test if the Authorization key is added in request headers, But I an able to get Response only and not able to figure out how to get the request header


Solution

  • Helper class:

    package de.scrum_master.stackoverflow.q74575745;
    
    class WebClientException extends RuntimeException {
      public WebClientException(Throwable cause) {
        super(cause);
      }
    }
    

    Class under test:

    package de.scrum_master.stackoverflow.q74575745;
    
    import okhttp3.Interceptor;
    import okhttp3.Request;
    import okhttp3.Response;
    
    import java.io.IOException;
    
    class AuthRequestInterceptor implements Interceptor {
      @Override
      public Response intercept(Interceptor.Chain chain) throws IOException {
        Request original = chain.request();
    
        // Request customization: add request headers
        Request.Builder requestBuilder = original.newBuilder()
          .header("Authorization", "auth-value");
    
        Request request = requestBuilder.build();
        return chain.proceed(request);
      }
    }
    

    Spock specification:

    In order to test your interceptor in isolation, just mock the interceptor chain parameter, making sure that it returns a request without headers. Then verify that the proceed(Request) method is called with a request parameter containing the header you expect.

    package de.scrum_master.stackoverflow.q74575745
    
    import okhttp3.Interceptor
    import okhttp3.Request
    import spock.lang.Specification
    
    class AuthRequestInterceptorTest extends Specification {
      def "request contains authorization header"() {
        given: "a mock interceptor chain returning a prepared request without headers"
        def chain = Mock(Interceptor.Chain) {
          request() >> new Request.Builder()
            .url("http://1.1.1.1/heath-check")
            .build()
        }
    
        when: "running the interceptor under test"
        new AuthRequestInterceptor().intercept(chain)
    
        then: "the expected authorization header is added to the request before proceeding"
        1 * chain.proceed({ Request request -> request.headers("Authorization") == ["auth-value"] })
      }
    }
    

    Try it in the Groovy Web Console.

    You probably want to learn about Spock argument constraints.