且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用Spring进行集成测试期间模拟外部服务器

更新时间:2022-03-17 23:15:48

在玩完各种场景之后,这是一种方法,它可以在对主代码进行最少干预的情况下实现所要求的内容

After playing a bit with various scenarios, here is the one way how can one achieve what was asked with minimal interventions to the main code

  1. 重构您的控制器以将参数用于第三方服务器地址:

  1. Refactor your controller to use a parameter for thirdparty server address:

@RestController
public class HelloController {
    @Value("${api_host}")
    private String apiHost;

    @RequestMapping("/hello_to_facebook")
    public String hello_to_facebook() {
        // Ask facebook about something
        HttpGet httpget = new HttpGet(buildURI("http", this.apiHost, "/oauth/access_token"));
        String response = httpClient.execute(httpget).getEntity().toString();
        // .. Do something with a response
        return response + "_PROCESSED";
    }
}

'api_host'等于src/main/resources中application.properties中的'graph.facebook.com'

'api_host' equals to 'graph.facebook.com' in application.properties in the src/main/resources

  1. 在src/test/java文件夹中创建一个模拟第三方服务器的新控制器.

  1. Create a new controller in the src/test/java folder that mocks the thirdparty server.

覆盖"api_host"以测试到"localhost".

Override 'api_host' for testing to 'localhost'.

为简便起见,以下是一个文件中第2步和第3步的代码:

Here is the code for steps 2 and 3 in one file for brevity:

@RestController
class FacebookMockController {
    @RequestMapping("/oauth/access_token")
    public String oauthToken() {
        return "TEST_TOKEN";
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest({"api_host=localhost",})
public class TestHelloControllerIT {        
    @Test
    public void getHelloToFacebook() throws Exception {
        String url = new URL("http://localhost:8080/hello_to_facebook").toString();
        RestTemplate template = new TestRestTemplate();
        ResponseEntity<String> response = template.getForEntity(url, String.class);
        assertThat(response.getBody(), equalTo("TEST_TOKEN_PROCESSED"));

        // Assert that facebook mock got called:
        // for example add flag to mock, get the mock bean, check the flag
    }
}

有没有更好的方法可以做到这一点?感谢所有反馈!

Is there a nicer way to do this? All feedback is appreciated!

P.S.这是我将这个答案放到更现实的应用程序中遇到的一些复杂问题:

P.S. Here are some complications I encountered putting this answer into more realistic app:

  1. Eclipse将测试和主要配置混合到类路径中,因此您可以通过测试类和参数来破坏主要配置: https://issuetracker.springsource.com/browse/STS-3882 使用gradle bootRun避免它

  1. Eclipse mixes test and main configuration into classpath so you might screw up your main configuration by test classes and parameters: https://issuetracker.springsource.com/browse/STS-3882 Use gradle bootRun to avoid it

如果已设置spring安全性,则必须在安全性配置中打开对模拟链接的访问权限.要附加到安全性配置而不是与主配置混淆,请执行以下操作:

You have to open access to your mocked links in the security config if you have spring security set up. To append to a security config instead of messing with a main configuration config:

@Configuration
@Order(1)
class TestWebSecurityConfig extends WebSecurityConfig {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/oauth/access_token").permitAll();
        super.configure(http);
    }
}

  • 在集成测试中点击https链接并不容易.我最终将TestRestTemplate与自定义请求工厂一起使用,并配置了SSLConnectionSocketFactory.

  • It is not straightforward to hit https links in integration tests. I end up using TestRestTemplate with custom request factory and configured SSLConnectionSocketFactory.