Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 16 Next »

Table Of Contents

Addresses:

  • CPS-95 - Getting issue details... STATUS
  • CPS-124 - Getting issue details... STATUS
  • CPS-128 - Getting issue details... STATUS

Overview

The CPS-RI module which is responsible for data persistence and retrieval from the database is based on
Spring Data framework. Following components are used:

  • Persistence service implementations (logic layer) → these are defined as Java classes
  • JPA repositories (data access layer) → these are defined as Java interfaces, corresponding objects
    are created by Spring framework at runtime

In order to reach the desirable level of reliability it's expected the functionality to be covered with tests.

While using unit tests is a common approach for Java application testing, it seems insufficient  in a context of testing the
actual data persistence/retrieval functionality:

  • Test covers a small slice of functionality while the major piece served by external services (Spring data framework,
    JDBC driver and database itself) remain not used (not tested)
  • JPA repositories can be only used as mocks to test the service implementation but JPA repositories are not subject
    for tests themselves because of definition as interfaces
  • The effort to setup the expected behaviors for JPA repository mocks is comparable with (or exceeds) the effort
    required to setup the actual data for same cases;

From other hand the benefits of using integration tests with real database instance are following:

  • All levels of abstraction are involved in tests, it means all of them are impacting on test results same way as within
    a deployed application
  • JPA repositories are subjects of test
  • Complete validation of expected behavior, including database schema initialization
  • Can be used on build, keeping desired level of reliability and consistency
  • Tests can be used on development stage making the database deployment (on dev environment) optional

Components

Components used to serve the integration tests are shown on diagram below.

  • Docker provides a container with running database instance which is used during the test
  • Test container component communicates with Docker via CLI (or Engine API depending on Docker deployment),
    manages required container to be created/started before test and stopped/removed after the test is completed
  • Test container component is used by JUnit test as a Class Rule 
  • The connection to test database is served using standard Spring framework components 

More details on implementation are below.

Test Containers

Running instance of database for integration test is provided by TestContainers Java library component. 

Docker availability is a prerequisite.

Test container life circle management

Test Containers library is integrated with JUnit via Rule interface implementation:

  • On start() method invocation the requested test container is created (if absent) within a Docker and started (if not running yet)
  • On stop() method invocation the test container is stopped and removed

If annotated as @Rule the test container creation/start then stop/removal operations will be performed for each test method.
If annotated as @ClassRule these operation will be performed for each test class.

In order to save the resources (and all tests execution time as result) the default TestContainer implementation was wrapped to custom
(singleton type of) artifact. This way the database test container is initialized only once for all the tests. The test container removal is
linked to JVM shutdown event to avoid this container remain running in docker.


NB. The default remaining test containers removal (on JVM termination) was served by dedicated RYUK container (part of TestContainers library).
However this container requires running as privileged one, so it was disabled in order make TestContainers available on Jenkins. It made it
necessary to explicitly invoke test container removal logic on JVM termination event.


@SpringBootTest

Using @SpringBootTest annotation for tests allows @Autowired Spring components (including JPA repository instances) initialization for testing
same way as it's done on regular Spring Boot application execution. However both CPS Spring Boot application class and associated configuration
are allocated in CPS-REST maven module which is cannot be accessed from CPS-RI module on build (when the tests classes are compiled and executed).

In order to fulfill the @SpringBootTest requirements and to properly initialize DataSource object substitutions for both Spring Boot application
class and configuration (DataSource properties) are set directly within CPS-RI module (test scope).



Database initialization notes

It should be taken into account the ports exposed for a test containers are defined dynamically to allow concurrent tests executions
and to avoid conflicts with containers already running within a Docker. It means the connection parameters for a newly created test container
require to be set before

Test template


Resources

Frameworks and libraries:

Tutorials:





  • No labels