Skip to content

Latest commit

 

History

History

wiremock

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

SpringBoot TestContainer

This project shows how to set up an spring boot project for running Integration test using TestContainers and Wiremock.

Table of contents

  1. Application Description

    1. Application process flow
    2. Application external dependencies
  2. Integration Test

    1. JPA Layer
    2. External Services
    3. End to End Test
  3. Setup Project

  4. References

Application Description

Next section shows application processing flow its dependencies:

Application process flow:

Main goal for this project, is receive a HTTP Request and process following next steps:

  1. Persist request: Save data request with NEW state into database.

  2. Get merchant configurations: Call an external web service to get the merchant configuration.

  3. Evaluate fraud: If merchant has enabled fraud validation option, it calls Fraud Control web service (update the request to EVALUATED status in database).

  4. WebHook for final state: If merchant has enabled web hook notifications, it sends an http post to the merchant web page. (update the request to NOTIFIED status in database).

NOTE:

  • If one error occurs, system update the record in ERROR state and return a HTTP response with error message.

Application external dependencies:

This project process a request using next 4 dependencies:

  1. ConfigurationService: External rest web service for getting up merchant configurations. Implementation using declarative Feign client.

  2. FraudControlService: External rest web service for evaluation/scoring fraud risk. Implementation using Spring RestTemplate.

  3. MerchantWebHook: External merchant web endpoint for receiving HTTP notifications. Implementation using Spring RestTemplate.

  4. DBMS: Relational database managment system for persisting process flow and process result. This project uses Postgres.


Integrations test

This section shows implementation integration test.

JPA Layer

Integration test using TestContainers. Find implementation in RepositoryIntegrationTest.java class.

Header annotation class has configuration for running jpa integration test:

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(initializers = RepositoryIntegrationTest.Initializer.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Testcontainers
public class RepositoryIntegrationTest {

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(initializers = RepositoryIntegrationTest.Initializer.class)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Testcontainers
public class RepositoryIntegrationTest {
@DataJpaTest:
  • Annotation for a JPA test that focuses only on JPA components.
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE):
  • NONE configuration do not replace the application default DataSource.
@Testcontainers:
  • Annotation to find all fields that are annotated with @Container and calls their container lifecycle methods.
@ContextConfiguration(initializers = RepositoryIntegrationTest.Initializer.class):
  • Spring Initializer for starting Postgres database container.

protected static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
TestPropertyValues
.of("spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(),
"spring.datasource.username=" + postgreSQLContainer.getUsername(),
"spring.datasource.password=" + postgreSQLContainer.getPassword())
.applyTo(configurableApplicationContext);
}
}

protected static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
	@Override
	public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
		TestPropertyValues
			.of("spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(),
				"spring.datasource.username=" + postgreSQLContainer.getUsername(),
				"spring.datasource.password=" + postgreSQLContainer.getPassword())
			.applyTo(configurableApplicationContext);
	}
}

External services

Integration test using Wiremock. Find implementation in AbstractClientConfiguration.java class.

Header annotation class has configuration for web client integration test:

@ContextConfiguration(classes = { AbstractClientConfiguration.ContextConfiguration.class })
@SpringBootTest(
properties = { "app.config-service.base-path=","app.fraud-service.base-path=http://localhost:${wiremock.server.port}/evaluate" },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = {FraudEvaluationClient.class, WebHookClient.class, RestTemplate.class })
@AutoConfigureWireMock(port = 0, stubs = "classpath*:/wiremock/**/mappings/**/*.json", files = "classpath:/wiremock")
public class AbstractClientConfiguration {

@ContextConfiguration(classes = { AbstractClientConfiguration.ContextConfiguration.class })
@SpringBootTest(
		properties = { "app.config-service.base-path=","app.fraud-service.base-path=http://localhost:${wiremock.server.port}/evaluate" }, 
		webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 
		classes = {FraudEvaluationClient.class, WebHookClient.class, RestTemplate.class })
@AutoConfigureWireMock(port = 0, stubs = "classpath*:/wiremock/**/mappings/**/*.json", files = "classpath:/wiremock")
public class AbstractClientConfiguration {
@ContextConfiguration:
  • Define which Spring @Configuration to load.
  • ContextConfiguration configuration class for prepare Feign clients and RestTemplateBuilder.
@SpringBootTest:
  • This annotation allow us to create the ApplicationContext used in integration tests via SpringApplication.
  • we override the external services base path for using WireMock endpoints.
@AutoConfigureWireMock:
  • Annotation to start a mock web server with our stubs and mapping definitions.

End to End test

End to End testing using Wiremock and TestContainers. Find implementation in AbtractIntegrationTest.java class.

Header annotation class has configuration for running End to End test:

@ContextConfiguration(initializers = AbtractIntegrationTest.Initializer.class, classes = {AbtractIntegrationTest.LocalRibbonClientConfiguration.class })
@SpringBootTest(properties = { "app.config-service.base-path=","app.fraud-service.base-path=http://localhost:${wiremock.server.port}/evaluate"}, webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWireMock(port = 0, stubs = "classpath*:/wiremock/**/mappings/**/*.json", files = "classpath:/wiremock")
@Testcontainers
public class AbtractIntegrationTest {

@ContextConfiguration(initializers = AbtractIntegrationTest.Initializer.class, classes = {AbtractIntegrationTest.LocalRibbonClientConfiguration.class })
@SpringBootTest(properties = { "app.config-service.base-path=","app.fraud-service.base-path=http://localhost:${wiremock.server.port}/evaluate"}, webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureWireMock(port = 0, stubs = "classpath*:/wiremock/**/mappings/**/*.json", files = "classpath:/wiremock")
@Testcontainers
public class AbtractIntegrationTest {
@ContextConfiguration:
  • Define which Spring @Configuration to load.
  • Initializer class set up a Postgres container.
  • LocalRibbonClientConfiguration class add wiremock port server for finding local endpoints.
@SpringBootTest:
  • This annotation allow us to create the ApplicationContext used in integration tests via SpringApplication.
  • we override the external services base path for using WireMock endpoints.
@AutoConfigureWireMock:
  • Annotation to start a mock web server with our stubs and mapping definitions.

Setup Project

  • Clone this repository
 git clone https://github.com/guedim/spring-projects.git
  • Move to the directory wiremock
cd spring-projects/wiremock

Run Integration Test

  • For running integration test (using WireMock and TestContainers with a Postgres database) execute next command:
mvn verify

References: