Я экспериментировал с Контрактным тестированием с использованием Spring Cloud Contract (SCC) и сейчас пытаюсь использовать Pact в сочетании с SCC, чтобы служить промежуточным этапом перед переходом на чистый Pact.
В моем потребительском проектеЯ указал простой контракт:
@RunWith(SpringRunner.class)
@SpringBootTest
public class AccountServicePactTest {
@Autowired
TransactionService transactionService;
@Rule
public PactProviderRuleMk2 mockProvider = new PactProviderRuleMk2("account-service", "localhost", 8081, this);
@Pact(consumer = "transaction-service")
public RequestResponsePact createPact(PactDslWithProvider builder) {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json;charset=UTF-8");
return builder
.given("An account with UUID 8ea0f76b-b7a6-49eb-b25c-073b664d2de3 exists")
.uponReceiving("Request for an account by UUID")
.path("/api/accounts/8ea0f76b-b7a6-49eb-b25c-073b664d2de3")
.method("GET")
.willRespondWith()
.headers(headers)
.status(200)
.body("{\n" +
" \"accountUUID\": \"8ea0f76b-b7a6-49eb-b25c-073b664d2de3\",\n" +
" \"customerId\": 1,\n" +
" \"balance\": 0.00,\n" +
"}")
.toPact();
}
@Test
@PactVerification
public void runTest() {
AccountRetrievalRequest request = new AccountRetrievalRequest(UUID.fromString("8ea0f76b-b7a6-49eb-b25c-073b664d2de3"));
AccountDTO accountDTO = transactionService.retrieveAccount(request);
assertThat(accountDTO.getAccountUUID()).isEqualTo(UUID.fromString("8ea0f76b-b7a6-49eb-b25c-073b664d2de3"));
}
}
(я знаю, что жесткое кодирование UUID, customerId и balance делает тест хрупким, но это всего лишь простой тест)
Использование пактаПлагин -jvm-provider-maven_2.12 (плагин провайдера на стороне потребителя, сбивающий с толку, я знаю) файл Pact передается в Pact Broker:
<plugin>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-maven_2.12</artifactId>
<version>3.5.22</version>
<configuration>
<pactBrokerUrl>http://localhost:8888</pactBrokerUrl>
<pactBrokerUsername></pactBrokerUsername>
<pactBrokerPassword></pactBrokerPassword>
<trimSnapshot>true</trimSnapshot>
</configuration>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>publish</goal>
</goals>
</execution>
</executions>
</plugin>
Пока все хорошо.
На проекте провайдера я сталкиваюсь с проблемами, пытающимися проверить контракт.Опять же, я использую SCC и Pact вместе.Фрагмент плагина pom.xml:
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract.version}</version>
<extensions>true</extensions>
<configuration>
<contractsRepositoryUrl>pact://http://localhost:8888</contractsRepositoryUrl>
<contractDependency>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>+</version>
</contractDependency>
<contractsMode>REMOTE</contractsMode>
<packageWithBaseClasses>com.abnamro.internship.bank.accountservice.pacts</packageWithBaseClasses>
</configuration>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-pact</artifactId>
<version>${spring-cloud-contract.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-maven_2.12</artifactId>
<version>3.5.11</version>
<configuration>
<serviceProviders>
<serviceProvider>
<name>account-service</name>
<pactBrokerUrl>http://localhost:8888/</pactBrokerUrl>
</serviceProvider>
</serviceProviders>
</configuration>
</plugin>
Требуется верификатор SCC Базовый класс:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AccountServiceApplication.class)
public abstract class Account_serviceContractsBase {
@Autowired
private WebApplicationContext webApplicationContext;
@Autowired
private AccountRepository accountRepository;
@Before
public void setup() {
Account account = new Account(UUID.fromString("8ea0f76b-b7a6-49eb-b25c-073b664d2de3"), Integer.toUnsignedLong(1),
0.00d);
accountRepository.save(account);
RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
System.out.println(account.getAccountUUID());
}
@After
public void teardown() {}
}
Тест, сгенерированный SCC:
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ContractsTest extends Account_serviceContractsBase {
@Test
public void validate_0_account_service_pact() throws Exception {
// given:
MockMvcRequestSpecification request = given();
// when:
ResponseOptions response = given().spec(request)
.get("/api/accounts/8ea0f76b-b7a6-49eb-b25c-073b664d2de3");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).isEqualTo("application/json;charset=UTF-8");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field("['accountUUID']").isEqualTo("8ea0f76b-b7a6-49eb-b25c-073b664d2de3");
assertThatJson(parsedJson).field("['customerId']").isEqualTo(1);
assertThatJson(parsedJson).field("['balance']").isEqualTo(0.0);
}
}
Запуск теста дает следующее исключение:
java.lang.IllegalArgumentException: json string can not be null or empty
Я не могу понять, почему строка является пустой или нулевой.Запуск приложения и использование Postman для проверки конечной точки работает просто отлично.
Это часть контроллера:
@RestController
@RequestMapping("/api")
public class AccountController {
...
@GetMapping("/accounts/{accountUUID}")
public ResponseEntity<Account> retrieveAccount(@PathVariable("accountUUID") UUID accountUUID) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
return new ResponseEntity<>(accountService.retrieveAccount(accountUUID),
httpHeaders, HttpStatus.OK);
}
Я что-то упустил, но не могу найти что.Мысли?
РЕДАКТИРОВАТЬ: (сгенерированный) тест пройден только при использовании SCC.