Spring과의 통합 테스트 중 외부 서버 모의 테스트
요청에 따라 서드파티 웹 API(예: Facebook oauth 토큰 검색)에 외부 호출을 하는 Spring 웹 서버가 있습니다.이 콜로부터 데이터를 취득하면, 다음과 같은 응답이 계산됩니다.
@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 오브젝트에 있습니다.하지만 테스트 코드는 URL을 누르기만 하면 응답을 기대할 수 있기 때문에 같은 코드라고 생각됩니다.
다양한 시나리오를 조금 사용한 후, 메인 코드에 대한 최소한의 개입으로 요구되는 것을 달성할 수 있는 방법은 다음과 같습니다.
컨트롤러가 서드파티 서버 주소에 파라미터를 사용하도록 리팩터링합니다.
@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/properties의 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 gradle bootRun을 사용하여 이를 회피합니다.
스프링 보안이 설정되어 있는 경우 보안 설정에서 조롱된 링크에 대한 액세스를 열어야 합니다.메인 Configuration을 조작하지 않고 보안 Configuration에 추가하려면 다음 절차를 수행합니다.
@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 링크를 히트하는 것은 간단하지 않습니다.커스텀 리퀘스트 팩토리 및 SSL Connection Socket Factory 설정이 끝난 TestRestTemplate를 사용하게 되었습니다.
Hello Controller 내에서 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
}
}
자동 배선에는 다음과 같은 공통 RestTemplateConfiguration이 필요합니다.
@Configuration
public class RestTemplateConfiguration {
/**
* A RestTemplate that compresses requests.
*
* @return RestTemplate
*/
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
또한 Hello Controller 내부에서도 사용해야 합니다.
@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;
}
}
2018년 상황이 많이 좋아졌다.나는 결국 그것을 이용하게 되었다.spring-cloud-contracts
여기 비디오 소개 https://www.youtube.com/watch?v=JEmpIDiX7LU가 있습니다.이 이야기의 첫 번째 부분에서는 레거시 서비스에 대해 설명합니다.외부 API에 사용할 수 있습니다.
요지는,
Groovy DSL 또는 명시적 콜/프록시 또는 녹음을 지원하는 다른 방법을 사용하여 외부 서비스 계약을 작성합니다.고객의 요구에 맞는 메뉴얼을 참조해 주세요.
이 경우 실제로는 서드파티를 제어할 수 없기 때문에
contract-verifier
stub를 로컬로 만들 수 있지만 잊지 말고skipTests
를 사용하여
stub-jar
이제 컴파일되어 사용할 수 있게 되었습니다.Wiremock이 실행되므로 테스트 케이스 내에서 실행할 수 있습니다.
이 질문과 여러 stackoverflow 답변이 솔루션을 찾는 데 도움이 되었습니다.이러한 테스트와 기타 유사한 마이크로 서비스 관련 테스트를 받은 다음 사용자를 위한 샘플프로젝트를 소개합니다.
https://github.com/abshkd/spring-cloud-sample-games
모든 것이 한번 작동하면, 당신은 결코 뒤돌아보지 않고 모든 테스트를 할 수 있습니다.spring-cloud-contracts
@marcin-grzejszczak 작가도 SO를 하고 있고, 그는 이것을 알아내는 데 많은 도움을 주었다.그래서 막히면 SO에 글을 올려주세요.
HelloController 클래스와 동일한 엔드포인트를 표시하는 다른 스프링컨피규레이션파일을 사용할 수 있습니다.그런 다음 json 응답을 반환할 수 있습니다.
당신의 코드로 볼 때, 당신이 무엇을 달성하려고 하는지 잘 모르겠습니다.단순히 Facebook 콜이 기능하는 것을 보고 싶다면 Facebook과 실제로 대화하는 서비스에 대해 테스트하는 것 외에 다른 방법이 없습니다.페이스북의 응답을 조롱하는 것은 그것이 올바르게 조롱되고 있는지 확인하기 위해 나를 매우 유용한 테스트라고 생각하지 않는다.
Facebook에서 반환되는 데이터가 어떤 방식으로든 변환되는지 테스트하고 있고, 그 데이터가 올바르게 처리되고 있는지 확인하고 싶다면, Facebook 응답을 매개 변수로 하여 그 변환을 실행하는 다른 방법으로 작업을 수행할 수 있습니다.그런 다음 다양한 json 입력을 기반으로 올바르게 작동하는지 확인할 수 있습니다.
웹 서비스를 전혀 도입하지 않고 테스트할 수 있습니다.
언급URL : https://stackoverflow.com/questions/29550098/mock-external-server-during-integration-testing-with-spring
'programing' 카테고리의 다른 글
Respect Js: Uncapted (in promise) SyntaxError:위치 0의 JSON에 예기치 않은 토큰이 있습니다. (0) | 2023.03.26 |
---|---|
레일이 jQuery에서 JSON을 올바르게 디코딩하지 않음(배열이 정수 키를 가진 해시가 됨) (0) | 2023.03.26 |
WordPress 4.8 on Docker REST API에 액세스할 수 없음 (0) | 2023.03.26 |
로컬 데이터베이스와 라이브 데이터베이스를 결합하는 방법 (0) | 2023.03.26 |
모바일 앱용 WooCommerce API (0) | 2023.03.26 |