Integration Testing Guidelines
Integration tests are critical for ensuring that your FlowInquiry backend components work together correctly. This guide covers how to write effective integration tests using TestContainers in the FlowInquiry ecosystem.
Benefits of Using TestContainers
TestContainers
- Realistic testing environment: Tests run against actual databases and services instead of mocks
- Consistency across environments: The same containers run in CI/CD pipelines and local development
- Isolation: Each test suite can use its own containerized dependencies
- Parallel test execution: TestContainers supports concurrent testing
- Simplified setup: No need to maintain external test infrastructure
- Comprehensive coverage: Test the full stack, including database interactions and external services
Writing Integration Tests in FlowInquiry
Test Data Management
FlowInquiry gets test data from the module tools/liquibase, and all test data files are located at the data/test folder. This provides an elegant way to handle test data:
- Test data files are organized in the
data/testfolder - The
tools/liquibasemodule manages these test data files - Add the
context="test"attribute to changesets containing test data:
<changeSet id="create-test-users" author="developer" context="test">
<insert tableName="users">
<column name="id" value="test-user-1"/>
<column name="username" value="testuser"/>
<column name="email" value="test@example.com"/>
</insert>
</changeSet>- These test changesets will only be applied during integration tests, keeping your development and production databases clean
Changeset for project table
<changeSet author="flowinquiry" id="000:07-insert-default-fw-project-data" runOnChange="true">
<loadData file="config/liquibase/tenant/data/test/fw_project_test.csv"
tableName="fw_project" separator=";">
<column name="id" type="NUMERIC" />
<column name="created_by" type="NUMERIC" />
<column name="created_at" type="TIMESTAMP" />
<column name="modified_by" type="NUMERIC" />
<column name="modified_at" type="TIMESTAMP" />
<column name="name" type="STRING" />
<column name="description" type="STRING" />
<column name="short_name" type="STRING" />
<column name="team_id" type="NUMERIC" />
<column name="status" type="STRING" />
<column name="start_date" type="TIMESTAMP" />
<column name="end_date" type="TIMESTAMP" />
</loadData>
<sql>SELECT setval('fw_project_id_seq', (SELECT MAX(id) FROM
fw_project));</sql>
</changeSet>CSV Test Data Example
Test data files are typically stored in CSV format with semicolon (;) separators. Here’s an example from fw_project_test.csv, which reflects the project table in the database:
id;created_by;created_at;modified_by;modified_at;name;description;short_name;team_id;status;start_date;end_date
1;1;2023-01-01T10:00:00;1;2023-01-01T10:00:00;Customer Portal;Customer-facing web portal;cust;1;Active;2023-01-02T00:00:00;2023-06-30T00:00:00
2;1;2023-01-05T09:30:00;1;2023-01-05T09:30:00;CRM System;Manage contacts and leads;crm;2;Active;2023-01-10T00:00:00;2023-07-31T00:00:00Each column in the CSV file has a specific meaning:
id: Unique identifier for the projectcreated_by: User ID who created the projectcreated_at: Timestamp when the project was createdmodified_by: User ID who last modified the projectmodified_at: Timestamp when the project was last modifiedname: Full name of the projectdescription: Detailed description of the projectshort_name: Abbreviated name/code for the projectteam_id: ID of the team responsible for the projectstatus: Current status of the project (e.g., “Active”)start_date: Project start dateend_date: Project end date
Writing Integration Tests
To create an integration test in FlowInquiry:
- Create a test class in the
src/test/javadirectory - Annotate the class with
@IntegrationTest:
@IntegrationTest
@Transactional
public class TicketServiceIT {
@Autowired
private UserService userService;
...
@Test
void shouldCreateTicketSuccessfully() {
TicketDTO ticketDTO = ticketMapper.toDto(ticketRepository.findById(2L).orElseThrow());
ticketDTO.setId(null);
ticketDTO.setConversationHealth(null);
TicketDTO savedTicket = ticketService.createTicket(ticketDTO);
assertThat(savedTicket).isNotNull();
ArgumentCaptor<NewTicketCreatedEvent> eventCaptor =
ArgumentCaptor.forClass(NewTicketCreatedEvent.class);
verify(spyEventPublisher, times(1)).publishEvent(eventCaptor.capture());
}
}The @IntegrationTest annotation handles:
- Starting the required containers (PostgreSQL, Redis, etc.)
- Applying database migrations with test context
- Configuring Spring to use the containerized services
- Cleaning up after tests complete
Running Integration Tests
Running in IDE
To run integration tests in your IDE:
- Make sure you have Docker installed and running
- Right-click on the test class and select “Run as JUnit Test”
- If you want to debug, right-click and choose “Debug as JUnit Test”
Most popular IDEs (IntelliJ IDEA, Eclipse, VS Code) support running these tests directly.
Running with Gradle
To run integration tests using Gradle:
./gradlew integrationTestThis will:
- Start the required Docker containers
- Execute all tests annotated with
@IntegrationTest - Generate test reports in the
apps/server/build/reports/jacocodirectory - Shut down and clean up containers after completion
If you want to run a specific integration test class:
./gradlew integrationTest --tests "io.flowinquiry.modules.teams.service.TicketServiceIT"