Spring Cloud Contract + Pact(代理):json字符串不能为null或为空

时间:2018-11-16 15:29:07

标签: spring-boot pact spring-cloud-contract

我一直在尝试使用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时,(生成的)测试通过。

1 个答案:

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