рд╡рд╕рдВрдд рдХреНрд▓рд╛рдЙрдб рдЕрдиреБрдмрдВрдз рдХреЗ рд╕рд╛рде рд╡реЗрдм рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдПрдХреАрдХрд░рдг


рдпрд╣ рд▓реЗрдЦ рд╕реНрдкреНрд░рд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдФрд░ рдПрдЪрдЯреАрдЯреАрдкреА рдкрд░ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦреЗ рдЧрдП рд╡реЗрдм рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рдПрдХреАрдХрд░рдг рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд░реЗрдЧрд╛ред рдореЗрд░реА рд░рд╛рдп рдореЗрдВ рд╕реНрдкреНрд░рд┐рдВрдЧ рдХреНрд▓рд╛рдЙрдб рдХреЙрдиреНрдЯреНрд░реИрдХреНрдЯ рдирд╛рдо рднреНрд░рд╛рдордХ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХрд╛ рдХреНрд▓рд╛рдЙрдб рд╕реЗ рдХреЛрдИ рд▓реЗрдирд╛-рджреЗрдирд╛ рдирд╣реАрдВ рд╣реИред


рдпрд╣ рдПрдкреАрдЖрдИ рдЕрдиреБрдмрдВрдзреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╣реЛрдЧрд╛ред


рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреА рдЗрдХрд╛рдИ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП, рдореЙрдХрдПрдорд╕реАрд╡реА рдпрд╛ рд░реЗрд╕реНрдЯрд╕реБрд░рд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдЕрдХреНрд╕рд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдореЛрдХреЗ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдХреЗ рдЫреЛрд░ рдкрд░ рдореЛрд╕реНрдХ рд╕рд░реНрд╡рд░ рдЬреИрд╕реЗ рд╡рд╛рдпрд░рдореЙрдХ рдпрд╛ рдкреИрдХреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЕрдХреНрд╕рд░, рдпреВрдирд┐рдЯ рдкрд░реАрдХреНрд╖рдг рдХреБрдЫ рд▓реЛрдЧреЛрдВ рдФрд░ рдЕрдиреНрдп рд▓реЛрдЧреЛрдВ рджреНрд╡рд╛рд░рд╛ рдореЛрдХреА рджреНрд╡рд╛рд░рд╛ рд▓рд┐рдЦреЗ рдЬрд╛рддреЗ рд╣реИрдВред


рдЗрд╕рд╕реЗ рдПрдХреАрдХрд░рдг рдХреЗ рд╕рд╛рде рд╕рдорд╕реНрдпрд╛рдПрдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВред


рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдбреЗрдЯрд╛ рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ рдореЗрдВ рдПрдХ рд╕рд░реНрд╡рд░ 204 NO_CONTENT рд▓реМрдЯрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдПрдХ рдЧреНрд░рд╛рд╣рдХ 200 OK рдФрд░ рдЦрд╛рд▓реА json рдХреА рдЙрдореНрдореАрдж рдХрд░ рд╕рдХрддрд╛ рд╣реИред


рдЗрд╕рд╕реЗ рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ рдкрдбрд╝рддрд╛ рдХрд┐ рдЙрдирдореЗрдВ рд╕реЗ рдХреМрди рд╕рд╣реА рд╣реИред рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рдиреЗ рдЧрд▓рддреА рдХреА рд╣реИ рдФрд░ рдпрд╣ рдПрдХреАрдХрд░рдг рдЪрд░рдг рд╕реЗ рдкрд╣рд▓реЗ рдирд╣реАрдВ рдорд┐рд▓реЗрдЧрд╛ред


рдЗрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╕реНрдкреНрд░рд┐рдВрдЧ рдХреНрд▓рд╛рдЙрдб рдЕрдиреБрдмрдВрдз рджреНрд╡рд╛рд░рд╛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред


рд╡рд╕рдВрдд рдмрд╛рджрд▓ рдЕрдиреБрдмрдВрдз рдХреНрдпрд╛ рд╣реИ


рдпрд╣ рдПрдХ рдлрд╛рдЗрд▓ рд╣реИ рдЬрд┐рд╕рдореЗрдВ yaml рдпрд╛ groovyDSL рдмреЛрд▓реА рдмрддрд╛рддреА рд╣реИ рдХрд┐ рдЕрдиреБрд░реЛрдз рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреИрд╕реЗ рджрд┐рдЦрдиреА рдЪрд╛рд╣рд┐рдПред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рд╕рднреА рдЕрдиреБрдмрдВрдз /src/test/resources/contracts/* рдлрд╝реЛрд▓реНрдбрд░ рдореЗрдВ рд╣реИрдВред


рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕рд░рд▓рддрдо GET-рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВ


 @GetMapping("/bets/{userId}") public ResponseEntity<List<Bet>> getBets(@PathVariable("userId") String userId) { List<Bet> bets = service.getByUserId(userId); if (bets.isEmpty()) { return ResponseEntity.noContent().build(); } return ResponseEntity.ok(bets); } 

рд╣рдо рдЕрдиреБрдмрдВрдз рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВрдЧреЗ


 org.springframework.cloud.contract.spec.Contract.make { request { method 'GET' urlPath '/bets/2' } response { status 200 headers { header('Content-Type', 'application/json') } body(''' { "sport":"football", "amount": 1 } ''' ) } } 

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпреВрдирд┐рдЯ рдЯреЗрд╕реНрдЯ рдФрд░ рд╡рд╛рдпрд░рд╕рди рдХреЗ рд▓рд┐рдП json рдЗрд╕ рдлрд╛рдЗрд▓ рд╕реЗ рдорд╛рд╡реЗрди рдпрд╛ рдЧреНрд░реЗрдбрд▓ рдкреНрд▓рдЧрдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрддреНрдкрдиреНрди рд╣реЛрддреЗ рд╣реИрдВ ред


рдКрдкрд░ рджрд┐рдП рдЧрдП рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдореЙрдХ рдХрд╛ JSON рд╡рд┐рд╡рд░рдг рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:


 { "id" : "df8f7b73-c242-4664-add3-7214ac6356ff", "request" : { "urlPath" : "/bets/2", "method" : "GET" }, "response" : { "status" : 200, "body" : "{\"amount\":1,\"sport\":\"football\"}", "headers" : { "Content-Type" : "application/json" }, "transformers" : [ "response-template" ] }, "uuid" : "df8f7b73-c242-4664-add3-7214ac6356ff" } 

рд╡рд╛рдпрд░рдореЙрдХ рдХреЛ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рдЪрд▓рд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЖрдкрдХреЛ рдмрд╕ рдпрд╣рд╛рдВ рд╕реЗ рдЬрд╛рд░ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, json mokee рдХреЛ mappings рдлрд╝реЛрд▓реНрдбрд░ рдбрд╛рд▓рдирд╛ рдЪрд╛рд╣рд┐рдПред


 $java -jar wiremock-standalone-2.18.0.jar 

рдиреАрдЪреЗ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рдЙрддреНрдкрдиреНрди рдкрд░реАрдХреНрд╖рдг рд╣реИред RestAssured рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди mockMVC рдпрд╛ spockframework рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред


 public class UserControllerTest extends ContractBae { @Test public void validate_get_200() throws Exception { // given: MockMvcRequestSpecification request = given(); // when: ResponseOptions response = given().spec(request) .get("/bets/2"); // then: assertThat(response.statusCode()).isEqualTo(200); assertThat(response.header("Content-Type")).isEqualTo("application/json"); // and: DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); assertThatJson(parsedJson).field("['amount']").isEqualTo(1); assertThatJson(parsedJson).field("['sport']").isEqualTo("football"); } } 

рдпрд╣ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рд╕рднреА рдЙрддреНрдкрдиреНрди рдХрдХреНрд╖рд╛рдПрдВ рдХреБрдЫ рдкреНрд░рдХрд╛рд░ рдХреЗ рдЖрдзрд╛рд░ рд╡рд░реНрдЧ (рдХрдИ рдЖрдзрд╛рд░ рдХрдХреНрд╖рд╛рдПрдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВ) рдкреНрд░рд╛рдкреНрдд рдХрд░рддреА рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдкреИрд░рд╛рдореАрдЯрд░ рдЖрд░рдВрдн рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдмреЗрд╕ рдХреНрд▓рд╛рд╕ рдХрд╛ рд░рд╛рд╕реНрддрд╛ рдкреНрд▓рдЧрдЗрди рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рд╣реИред


рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдмреЗрд╕ рдХреНрд▓рд╛рд╕ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦ рд╕рдХрддрд╛ рд╣реИ:


 @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SccDemoApplication.class) public abstract class ContractBae { @LocalServerPort int port; @Autowired protected WebApplicationContext webApplicationContext; @Before public void configureRestAssured() { RestAssured.port = port; MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) .build(); RestAssuredMockMvc.mockMvc(mockMvc); } } 

рдирддреАрдЬрддрди, рд╣рдореЗрдВ рдкрддрд╛ рдЪрд▓рддрд╛ рд╣реИ рдХрд┐ рдкрд░реАрдХреНрд╖рдг рдФрд░ рдореЛрдХреЗ рджреЛрдиреЛрдВ рдПрдХ рд╕реНрд░реЛрдд рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдП рдЧрдП рдереЗред рдпрджрд┐ рдпреВрдирд┐рдЯ рдкрд░реАрдХреНрд╖рдг рдкрд╛рд╕ рд╣реЛ рдЬрд╛рддреЗ рд╣реИрдВ рдФрд░ рд╕рд╢рд░реНрдд рдореЛрд░реНрдЪреЗ рдкрд░ рдореЛрдХрд╛рд╕ рдкрд░ рдЪрд▓рддрд╛ рд╣реИ, рддреЛ рдПрдХреАрдХрд░рдг рдХреЗ рд╕рд╛рде рдХреЛрдИ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реЛрдЧреАред


рд▓реЗрдХрд┐рди рдпрд╣ рд╕рдм рдирд╣реАрдВ рд╣реИ
рдореЛрдХреА рди рдХреЗрд╡рд▓ рд╕рд╛рдордиреЗ рдХреЗ рдЫреЛрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рджреВрд╕рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдПрдХреАрдХреГрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПред рд╕реНрдкреНрд░рд┐рдВрдЧ рдПрдХ рдорд╕реНрдХ рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рдЖрдкрдХреЛ рдмрд╕ рдореЛрдХрд╛рдореА рдХреЗ рд╕рд╛рде рдПрдХ рдЬрд╛рд░ рдЙрддреНрдкрдиреНрди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рдЗрд╕реЗ рдкрде рдХреЛ рдкрд╛рд╕ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ @AutoConfigureStubRunner рдПрдиреЛрдЯреЗрд╢рди


рдорд╛рди рд▓реАрдЬрд┐рдП рдХрд┐ рд╣рдорд╛рд░рд╛ рдХрдВрдЯреНрд░реЛрд▓рд░ рдХрд┐рд╕реА рдЕрдиреНрдп рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП HTTP рдХрд░рддрд╛ рд╣реИ:


 @GetMapping("/bets/{userId}") public ResponseEntity<List<Bet>> getBets(@PathVariable("userId") String userId) { if(!isUsetExists(userId)) { return ResponseEntity.notFound().build(); } List<Bet> bets = service.getByUserId(userId); if (bets.isEmpty()) { return ResponseEntity.noContent().build(); } return ResponseEntity.ok(bets); } private boolean isUsetExists(String userId) { try { restTemplate.getForObject("/exists/" + userId, Void.class); return true; } catch (HttpStatusCodeException ignore) { return false; } } 

рдлрд┐рд░ рдЖрдкрдХреЛ рдмрд╕ рдЖрдзрд╛рд░ рд╡рд░реНрдЧ рдореЗрдВ рдореЛрдХрд╛рдореА рдХреЗ рд╕рд╛рде рд▓реЗ рдЬрд╛рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ


 @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SccDemoApplication.class) @AutoConfigureStubRunner(ids = {"me.dehasi.contracts.demo:sub-service-stubs:+:stubs:8090"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL) public abstract class ContractBase { 

рдХреНрдпреЛрдВрдХрд┐ рдпреЗ рдирд┐рдпрдВрддреНрд░рдХ рдкрд░реАрдХреНрд╖рдг рд╣реИрдВ, рдлрд┐рд░ рдЕрд╕рд┐рд╕реА-рдбреЙрдХ рд╕реНрдирд┐рдкреЗрдЯреНрд╕ рд╕рдорд╛рди рдкрд░реАрдХреНрд╖рдгреЛрдВ рд╕реЗ рдЙрддреНрдкрдиреНрди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ (рдмрд╛рдХреА рдбреЙрдХреНрд╕ рдкрд░ рдПрдХ рдкреВрд░реНрдг рд▓реЗрдЦ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╣рдм рдкрд░ рд╣реИ )ред


рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреНрдпрд╛ рд╣реИ?
рдпрд╣ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдкреАрдЖрдИ рдЕрдиреБрдмрдВрдз рдХрд╛ рдПрдХ рд╕реНрд░реЛрдд рд╣реИ, рдЬрд┐рд╕реЗ рдорд╛рдирд╡-рдкрдардиреАрдп рднрд╛рд╖рд╛ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдЗрд╕рдореЗрдВ рд╕реЗ рд╣рдо рдпреВрдирд┐рдЯ рдкрд░реАрдХреНрд╖рдг (рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рд░реВрдк рд╕реЗ рджрд╕реНрддрд╛рд╡реЗрдЬ рднреА) рдЙрддреНрдкрдиреНрди рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдореЛрдХреА рд╕реЗред рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╡реЗрдм рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рдмреАрдЪ рдПрдХреАрдХрд░рдг рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдЬреЛрдЦрд┐рдо рдХреЛ рдХрдо рдХрд░рддрд╛ рд╣реИред


рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рд╡реЗрдмрд╕рд╛рдЗрдЯ рдкрд░ рдЙрджрд╛рд╣рд░рдг рджреЗрдЦреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред


рд▓реЗрдЦ рдореЗрдВ рдХреЛрдб рдЙрджрд╛рд╣рд░рдг рдпрд╣рд╛рдВ рд╕рд░рд▓рддрдо рдкрд░рд┐рдпреЛрдЬрдирд╛ рд╕реЗ рд▓рд┐рдП рдЧрдП рд╣реИрдВ ред

Source: https://habr.com/ru/post/hi424057/


All Articles