oto*_*nan 13 spring integration-testing spring-security spring-boot
我有一个Spring Web服务器,根据请求对某些第三方Web API进行外部调用(例如,retreive 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;
}
}
Run Code Online (Sandbox Code Playgroud)
我正在编写一个集成测试,检查在我的服务器上点击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();
}
}
Run Code Online (Sandbox Code Playgroud)
实际的实际设置更复杂 - 我正在进行Facebook oauth登录,所有逻辑都不在控制器中,而是在各种Spring Security对象中.但是我怀疑测试代码应该是相同的,因为我只是在点击网址并期待响应,不是吗?
小智 7
如果您在 HelloController 中使用 RestTemplate,您将能够测试它 MockRestServiceTest,如下所示:https: //www.baeldung.com/spring-mock-rest-template#using-spring-test
在这种情况下
@RunWith(SpringJUnit4ClassRunner.class)
// Importand we need a working environment
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TestHelloControllerIT {
@Autowired
private RestTemplate restTemplate;
// Available by default in SpringBootTest env
@Autowired
private TestRestTemplate testRestTemplate;
@Value("${api_host}")
private String apiHost;
private MockRestServiceServer mockServer;
@Before
public void init(){
mockServer = MockRestServiceServer.createServer(this.restTemplate);
}
@Test
public void getHelloToFacebook() throws Exception {
mockServer.expect(ExpectedCount.manyTimes(),
requestTo(buildURI("http", this.apiHost, "/oauth/access_token"))))
.andExpect(method(HttpMethod.POST))
.andRespond(withStatus(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body("{\"token\": \"TEST_TOKEN\"}")
);
// You can use relative URI thanks to TestRestTemplate
ResponseEntity<String> response = testRestTemplate.getForEntity("/hello_to_facebook", String.class);
// Do the test you need
}
}
Run Code Online (Sandbox Code Playgroud)
请记住,您需要一个通用的 RestTemplateConfiguration 来进行自动装配,如下所示:
@Configuration
public class RestTemplateConfiguration {
/**
* A RestTemplate that compresses requests.
*
* @return RestTemplate
*/
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
Run Code Online (Sandbox Code Playgroud)
而且你也必须在 HelloController 中使用它
@RestController
public class HelloController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/hello_to_facebook")
public String hello_to_facebook() {
String response = restTemplate.getForEntity(buildURI("https", "graph.facebook.com", "/oauth/access_token"), String.class).getBody();
// .. Do something with a response
return response;
}
}
Run Code Online (Sandbox Code Playgroud)
在演绎了各种场景之后,这里有一种方法可以通过对主代码的最小干预来实现所要求的内容
重构您的控制器以使用第三方服务器地址的参数:
@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";
}
}
Run Code Online (Sandbox Code Playgroud)'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
}
}
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来做到这一点?所有反馈表示赞赏!
PS以下是我遇到的一些复杂问题,将此答案放入更逼真的应用程序:
Eclipse将测试和主要配置混合到类路径中,因此您可能会通过测试类和参数搞砸主配置:https://issuetracker.springsource.com/browse/STS-3882使用gradle bootRun来避免它
如果设置了spring安全性,则必须在安全性配置中打开对模拟链接的访问权限.要附加到安全配置而不是弄乱主配置配置:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)在集成测试中点击https链接并不简单.我最终使用TestRestTemplate与自定义请求工厂和配置SSLConnectionSocketFactory.
| 归档时间: |
|
| 查看次数: |
10163 次 |
| 最近记录: |