RestTemplate (TestRestTemplate)のfollow redirectsを無効にする


日本語だとなんと言えば良いのか分からないが、follow redirectsってあるじゃないですか。302 Foundなどが返ってくると、HTTPクライアントが自動的にLocationを見て、再度そちらにリクエスト投げてくれるやつ。これ、アプリケーションを作成するときはHTTPクライアントの機能として大変便利だと思います。

ただテストのときは無効にしてえ〜〜〜とも思います。

Spring BootにはRestTemplate、というかTestRestTemplateがありますが、これ、デフォルトだとfollow redirectsが有効です。

というわけで無効にしましょう。無効にするにはClientHttpRequestFactoryと、それを適用したTestRestTemplateをDIすればOKです。

follow redirectsを無効にしたClientHttpRequestFactoryの生成

まずfollow redirectsを無効にします。これはTestRestTemplateに与えられるClientHttpRequestFactoryにて設定します。

HTTPクライアントに利用するライブラリによって実装クラスが異なるため、微妙に設定方法も変わってきます。

org.apache.http.client.HttpClient

たぶんこれで良い…… と思う。手元に環境がなかったため未確認。

import org.apache.http.client.HttpClient

// org.apache.http.client.HttpClient用のClientHttpRequestFactory
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory

// ...

val client = HttpClientBuilder.create()
    .disableRedirectHandling()
    .build()
HttpComponentsClientHttpRequestFactory(client)

okhttp3.OkHttpClient

こっちは確認済み。

import okhttp3.OkHttpClient

// okhttp3.OkHttpClient用のClientHttpRequestFactory
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory

// ...

val client = OkHttpClient().newBuilder()
    .followRedirects(false)
    .build()
OkHttp3ClientHttpRequestFactory(client)

java.net.HttpURLConnection

こっちも確認済み。

これは外からjava.net.HttpURLConnectionを与えるわけではないので、他とはちょっと違う感じになる。

import java.net.HttpURLConnection

// java.net.HttpURLConnection用のClientHttpRequestFactory
import org.springframework.http.client.SimpleClientHttpRequestFactory

// ...

object : SimpleClientHttpRequestFactory() {
    override fun prepareConnection(connection: HttpURLConnection, httpMethod: String) {
        super.prepareConnection(connection, httpMethod)
        connection.instanceFollowRedirects = false
    }
}

ClientHttpRequestFactoryを適用したTestRestTemplateをDI

まずTestRestTemplateのBeanを定義する。以下は利用するHTTPクライアントがOkHttp3の場合ですが、他の場合は適宜与えるClientHttpRequestFactoryを変えてあげてください。

@TestConfiguration
class TestRestTemplateConfig {

    @Bean 
    fun testRestTemplate(): TestRestTemplate =
        TestRestTemplate(RestTemplateBuilder().requestFactory {
            val client = OkHttpClient().newBuilder()
                .followRedirects(false)
                .build()
            OkHttp3ClientHttpRequestFactory(client)
        })
}

最後にテストクラスでDIする。

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Imports(TestRestTemplateConfig::class)
class SomeTest(
    private val testRestTemplate: TestRestTemplate,
    @LocalServerPort private val port: Int
) : StringSpec({
    // ...
})