Testing 如何测试Apache HttpClient RequestConfig值是否正确设置?没有公众人物在场

Testing 如何测试Apache HttpClient RequestConfig值是否正确设置?没有公众人物在场,testing,private-members,apache-commons-httpclient,Testing,Private Members,Apache Commons Httpclient,我有这个类来配置一个HttpClient实例: package com.company.fraud.preauth.service.feignaccertifyclient; import com.company.fraud.preauth.config.ProviderClientConfig; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org

我有这个类来配置一个
HttpClient
实例:

package com.company.fraud.preauth.service.feignaccertifyclient;

    import com.company.fraud.preauth.config.ProviderClientConfig;
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.ssl.SSLContextBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    import java.security.KeyManagementException;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;


    @Slf4j
    @Configuration
    @RequiredArgsConstructor
    public class FeignClientConfig {

        private final ProviderClientConfig providerClientConfig;

        public HttpClient buildHttpClient() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
            RequestConfig.Builder requestBuilder = RequestConfig.custom();
            requestBuilder.setConnectTimeout(providerClientConfig.getConnectionTimeout());
            requestBuilder.setConnectionRequestTimeout(providerClientConfig.getConnectionRequestTimeout());
            requestBuilder.setSocketTimeout(providerClientConfig.getSocketTimeout());
            SSLContextBuilder builder = new SSLContextBuilder();
            builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());

            return HttpClientBuilder.create()
                    .setMaxConnPerRoute(providerClientConfig.getMaxConnectionNumber())
                    .setDefaultRequestConfig(requestBuilder.build())
                    .setSSLContext(builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()).build())
                    .build();
        }
    }
如何对该类进行单元测试,以查看生成的
HttpClient
是否正确设置了这些值

httpClient
我无法访问其
RequestConfig

我知道这两个帖子:

(这个问题中的投票数表明,在测试中这是一个并行且有争议的话题,我的情况可能会提供一个例子,说明为什么我们应该在测试中研究实例的内部状态,尽管它是私有的)

(它展示了一种在代码中添加拦截器以检查配置值的方法,但我不喜欢它,因为我想用功能代码分离测试)

有办法吗?我知道这门课应该考,对吧?你不能盲目地相信它会起作用;检查“notNull”对我来说似乎很脆弱


此链接可能会为我指明正确的方向:


它使用
PowerMock.Whitebox
检查实例的内部状态。

所以我检查了
PowerMock.Whitebox
源代码,结果发现反射是在内部使用的。而且,据说PowerMock与JUnit5还不兼容(到目前为止),我不想仅仅为了测试而添加另一个依赖项,所以我将使用反射进行测试

package com.company.fraud.preauth.service.feignaccertifyclient;

import com.company.fraud.preauth.config.PreAuthConfiguration;
import com.company.fraud.preauth.config.ProviderClientConfig;
import com.company.fraud.preauth.config.StopConfiguration;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.lang.reflect.Field;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {
        PreAuthConfiguration.class,
        StopConfiguration.class,
})
public class FeignClientConfigTest {

    @Mock
    private ProviderClientConfig providerClientConfig;

    @Test
    @DisplayName("should return HttpClient with defaultConfig field filled with values in providerClientConfig")
    public void shouldReturnHttpClientWithConfiguredValues() throws Exception {
        // given
        when(providerClientConfig.getConnectionRequestTimeout()).thenReturn(30000);
        when(providerClientConfig.getConnectionTimeout()).thenReturn(30);
        when(providerClientConfig.getMaxConnNumPerRoute()).thenReturn(20);
        when(providerClientConfig.getSocketTimeout()).thenReturn(10);
        FeignClientConfig feignClientConfig = new FeignClientConfig(providerClientConfig);

        // when
        HttpClient httpClient = feignClientConfig.buildHttpClient();

        // then
        // I want to test internal state of built HttpClient and this should be checked
        // I tried to use PowerMock.Whitebox, but then I found it uses reflection internally
        // I don't want to introduce another dependency, and PowerMock is said not to be compatible with JUnit 5, so..
        Field requestConfigField = httpClient.getClass().getDeclaredField("defaultConfig");
        requestConfigField.setAccessible(true);
        RequestConfig requestConfig = (RequestConfig)requestConfigField.get(httpClient);
        assertThat(requestConfig.getConnectionRequestTimeout(), equalTo(30000));
        assertThat(requestConfig.getConnectTimeout(), equalTo(30));
        assertThat(requestConfig.getSocketTimeout(), equalTo(10));
    }

}

此外,我还回答了OP中关于何时测试类中的私有成员的第一个问题,因此我检查了
PowerMock.Whitebox
源代码,结果发现反射是在内部使用的。而且,据说PowerMock与JUnit5还不兼容(到目前为止),我不想仅仅为了测试而添加另一个依赖项,所以我将使用反射进行测试

package com.company.fraud.preauth.service.feignaccertifyclient;

import com.company.fraud.preauth.config.PreAuthConfiguration;
import com.company.fraud.preauth.config.ProviderClientConfig;
import com.company.fraud.preauth.config.StopConfiguration;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.lang.reflect.Field;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {
        PreAuthConfiguration.class,
        StopConfiguration.class,
})
public class FeignClientConfigTest {

    @Mock
    private ProviderClientConfig providerClientConfig;

    @Test
    @DisplayName("should return HttpClient with defaultConfig field filled with values in providerClientConfig")
    public void shouldReturnHttpClientWithConfiguredValues() throws Exception {
        // given
        when(providerClientConfig.getConnectionRequestTimeout()).thenReturn(30000);
        when(providerClientConfig.getConnectionTimeout()).thenReturn(30);
        when(providerClientConfig.getMaxConnNumPerRoute()).thenReturn(20);
        when(providerClientConfig.getSocketTimeout()).thenReturn(10);
        FeignClientConfig feignClientConfig = new FeignClientConfig(providerClientConfig);

        // when
        HttpClient httpClient = feignClientConfig.buildHttpClient();

        // then
        // I want to test internal state of built HttpClient and this should be checked
        // I tried to use PowerMock.Whitebox, but then I found it uses reflection internally
        // I don't want to introduce another dependency, and PowerMock is said not to be compatible with JUnit 5, so..
        Field requestConfigField = httpClient.getClass().getDeclaredField("defaultConfig");
        requestConfigField.setAccessible(true);
        RequestConfig requestConfig = (RequestConfig)requestConfigField.get(httpClient);
        assertThat(requestConfig.getConnectionRequestTimeout(), equalTo(30000));
        assertThat(requestConfig.getConnectTimeout(), equalTo(30));
        assertThat(requestConfig.getSocketTimeout(), equalTo(10));
    }

}

此外,我还回答了OP中的第一个问题,关于何时在类中测试私有成员,Whitebox为我工作。由于此处没有记录,我将添加我的版本:

在我的例子中,我想测试超时是否与0不同,以避免死锁

    HttpClient httpClient = factory.getHttpClient();

    RequestConfig sut = Whitebox.getInternalState(httpClient, "defaultConfig");

    assertNotEquals(0, sut.getConnectionRequestTimeout());
    assertNotEquals(0, sut.getConnectTimeout());
    assertNotEquals(0, sut.getSocketTimeout());

Whitebox为我工作。由于此处没有记录,我将添加我的版本:

在我的例子中,我想测试超时是否与0不同,以避免死锁

    HttpClient httpClient = factory.getHttpClient();

    RequestConfig sut = Whitebox.getInternalState(httpClient, "defaultConfig");

    assertNotEquals(0, sut.getConnectionRequestTimeout());
    assertNotEquals(0, sut.getConnectTimeout());
    assertNotEquals(0, sut.getSocketTimeout());
Hm.
getInternalState()
在Mockito的更高版本中被弃用,并且它一直在
internal
的包中。这是不使用它的另一个原因
getInternalState()
在Mockito的更高版本中被弃用,并且它一直在
internal
的包中。这是不使用它的另一个原因。