我有一个 Spring Web 服务器,它根据请求对某些第三方 Web API 进行外部调用(例如检索 Facebook oauth 令牌)。从该调用获取数据后,它会计算响应:
@RestController
public class HelloController {
@RequestMapping("/hello_to_facebook")
public String hello_to_facebook() {
// Ask facebook about something
HttpGet httpget = new HttpGet(buildURI("https", "graph.facebook.com", "/oauth/access_token"));
String response = httpClient.execute(httpget).getEntity().toString();
// .. Do something with a response
return response;
}
}
我正在编写一个集成测试,检查在我的服务器上点击 url 是否会产生一些预期的结果。不过,我想在本地模拟外部服务器,这样我什至不需要访问互联网来测试这一切。做这个的最好方式是什么?
我是春天的新手,这就是我目前所拥有的。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest({})
public class TestHelloControllerIT {
@Test
public void getHelloToFacebook() throws Exception {
String url = new URL("http://localhost:8080/hello_to_facebook").toString();
//Somehow setup facebook server mock ...
//FaceBookServerMock facebookMock = ...
RestTemplate template = new TestRestTemplate();
ResponseEntity<String> response = template.getForEntity(url, String.class);
assertThat(response.getBody(), equalTo("..."));
//Assert that facebook mock got called
//facebookMock.verify();
}
}
实际的设置更复杂——我正在进行 Facebook oauth 登录,所有逻辑都不在控制器中,而是在各种 Spring Security 对象中。但是我怀疑测试代码应该是相同的,因为我只是点击网址并期望得到响应,不是吗?
在尝试了各种场景之后,这是一种如何在对主代码进行最少干预的情况下实现所要求的目标的一种方法
-
重构您的控制器以使用第三方服务器地址的参数:
@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'
在 src/test/java 文件夹中创建一个新的控制器来模拟第三方服务器。
覆盖“api_host”以测试“localhost”。
为了简洁起见,以下是将步骤 2 和 3 的代码放在一个文件中:
@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
}
}
有更好的方法来做到这一点吗?感谢所有反馈!
附:以下是我将这个答案放入更现实的应用程序时遇到的一些复杂情况:
Eclipse 将测试和主配置混合到类路径中,因此您可能会通过测试类和参数搞砸主配置:https://issuetracker.springsource.com/browse/STS-3882 https://issuetracker.springsource.com/browse/STS-3882使用 gradle bootRun 来避免它
-
如果您设置了 Spring Security,则必须在安全配置中打开对模拟链接的访问。要附加到安全配置而不是弄乱主配置配置:
@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 链接并不简单。我最终使用带有自定义请求工厂和配置的 SSLConnectionSocketFactory 的 TestRestTemplate。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)