Spring Cloud Contract + Pact(经纪人):json 字符串不能为 null 或为空

Spring Cloud Contract + Pact (Broker): json string can not be null or empty

我一直在尝试使用 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 验证程序基础 Class:

@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

我不明白为什么该字符串为空或 null。 运行 应用程序和使用 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 时通过。

原来我的 Base Class 没有正确设置。 Working Base Class 简单地模拟调用的服务方法和 returns 一个测试帐户:

@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() {}
}