我一直在尝试使用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进行硬编码会使测试变脆,但这只是一个简单的测试)
使用pact-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时,(生成的)测试通过。
答案 0 :(得分:1)
原来我的基本类设置不正确。工作基类,仅模拟被调用的服务方法并返回测试帐户:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AccountServiceApplication.class)
public abstract class Account_serviceContractsBase {
@Autowired
private WebApplicationContext webApplicationContext;
@MockBean
private AccountService accountService;
@Before
public void setup() {
Account account = new Account();
account.setAccountUUID(UUID.fromString("8ea0f76b-b7a6-49eb-b25c-073b664d2de3"));
account.setCustomerId(1L);
account.setBalance(0.00d);
when(accountService.retrieveAccount(UUID.fromString("8ea0f76b-b7a6-49eb-b25c-073b664d2de3"))).thenReturn(account);
RestAssuredMockMvc.webAppContextSetup(webApplicationContext);
}
@After
public void teardown() {}
}