Week 7 Day 5 — Integration Testing and Final Testing Review for Spring Professional Exam
Goal
Today I want to finish the testing topic for the Spring Professional exam.
Main questions:
- What is an integration test?
- What does
@SpringBootTestdo? - When should I use
@SpringBootTest? - What is the difference between
@SpringBootTestand slice tests? - How do I test full web flows with MockMvc?
- How do I test with a real HTTP port?
- How do I test with Testcontainers?
- How do transactions and rollback work in tests?
- What testing knowledge is enough for Spring Professional exam?
- What are the most important exam traps?
1. Quick Review from Week 7
In Week 7, I learned:
- Unit tests test one class without Spring.
@WebMvcTesttests the MVC/controller slice.@DataJpaTesttests the JPA/repository slice.@SpringBootTestloads the full Spring Boot application context.- MockMvc tests HTTP behavior without a real server.
TestEntityManagerhelps in JPA tests.spring-security-testhelps test secured endpoints.- Testcontainers can provide real infrastructure for integration tests.
Memory sentence:
Choose the smallest test that proves the behavior.
2. What Is an Integration Test?
An integration test checks that multiple parts of the application work together.
Examples:
Controller + Service + Repository
Security + Controller + Service
Service + Repository + Database
Application configuration + Beans
REST API + Database
Application + external service mock
A unit test asks:
Does this class work alone?
An integration test asks:
Do these parts work together?
Memory sentence:
Integration tests prove collaboration between components.
3. What Is @SpringBootTest?
@SpringBootTest loads the Spring Boot application context.
Example:
@SpringBootTest
class ApplicationContextTest {
@Test
void contextLoads() {
}
}
This checks:
Can Spring start the application context?
Can beans be created?
Can dependencies be injected?
Is configuration valid?
Does auto-configuration work?
Memory sentence:
@SpringBootTeststarts the full Spring Boot context.
4. Why contextLoads Is Useful
A simple test:
@SpringBootTest
class ApplicationContextTest {
@Test
void contextLoads() {
}
}
It looks empty, but it is not useless.
It proves:
Spring can start the application.
No required bean is missing.
Configuration properties are valid enough.
Bean dependencies can be wired.
But it does not prove business behavior.
Memory sentence:
contextLoadschecks startup, not features.
5. When Should I Use @SpringBootTest?
Use @SpringBootTest when I need:
full application context
real service beans
real repositories
real security configuration
multiple layers together
application configuration
external integration setup
Testcontainers
full request flow
Do not use it for every test.
For simple service logic:
unit test is better
For controller only:
@WebMvcTest is better
For repository only:
@DataJpaTest is better
Memory sentence:
Use
@SpringBootTestonly when the test needs the full app.
6. @SpringBootTest vs Slice Tests
| Test | Scope | Good for |
|---|---|---|
| Unit test | one class, no Spring | business logic |
@WebMvcTest | MVC slice | controllers, validation, JSON |
@DataJpaTest | JPA slice | repositories, mappings, queries |
@SpringBootTest | full app context | integration flow |
Memory sentence:
Slice tests are focused.
SpringBootTest is complete.
7. @SpringBootTest with MockMvc
For full web integration without real server:
@SpringBootTest
@AutoConfigureMockMvc
class TaskApiIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void createsTask() throws Exception {
mockMvc.perform(post("/api/tasks")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"title": "Learn Integration Tests"
}
"""))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.title").value("Learn Integration Tests"));
}
}
This can test:
Spring Security filters
Controller
Validation
Service
Repository
Database
JSON serialization
Exception handling
Memory sentence:
@SpringBootTest + MockMvctests a full MVC flow without starting a real server.
8. Example Full Flow Test
Feature:
POST /api/tasks creates a task.
GET /api/tasks/{id} returns the task.
Test:
@SpringBootTest
@AutoConfigureMockMvc
class TaskApiIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void createsAndReadsTask() throws Exception {
MvcResult createResult = mockMvc.perform(post("/api/tasks")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"title": "Integration Task"
}
"""))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.title").value("Integration Task"))
.andReturn();
String responseBody = createResult.getResponse().getContentAsString();
Long taskId = JsonPath.read(responseBody, "$.id");
mockMvc.perform(get("/api/tasks/{id}", taskId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(taskId))
.andExpect(jsonPath("$.title").value("Integration Task"));
}
}
This proves many layers work together.
Memory sentence:
Integration tests can test a realistic user flow.
9. @SpringBootTest Web Environment
@SpringBootTest can run with different web environments.
Common modes:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
Meaning:
| Mode | Meaning |
|---|---|
MOCK | mock servlet environment, no real server |
RANDOM_PORT | starts real server on random port |
DEFINED_PORT | starts real server on configured port |
NONE | no web environment |
Memory sentence:
MOCKis common with MockMvc;RANDOM_PORTstarts a real server.
10. Real HTTP Test with Random Port
Example:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TaskApiRealHttpTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void healthEndpointIsAvailable() {
ResponseEntity<String> response =
restTemplate.getForEntity("/actuator/health", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}
This starts an embedded server on a random port.
Useful when I want to test:
real HTTP layer
real server behavior
HTTP client behavior
full request/response stack
Memory sentence:
Use
RANDOM_PORTwhen I want real HTTP.
11. MockMvc vs TestRestTemplate
| Tool | Server? | Good for |
|---|---|---|
| MockMvc | no real server | MVC integration tests |
| TestRestTemplate | real server | real HTTP integration tests |
MockMvc:
mockMvc.perform(get("/api/tasks"))
TestRestTemplate:
restTemplate.getForEntity("/api/tasks", String.class)
Memory sentence:
MockMvc is serverless; TestRestTemplate uses real HTTP.
12. Integration Test with Database
A full integration test may use:
Controller
Service
Repository
Database
Example:
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
class TaskIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private TaskRepository taskRepository;
@Test
void createdTaskIsStoredInDatabase() throws Exception {
mockMvc.perform(post("/api/tasks")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"title": "Stored Task"
}
"""))
.andExpect(status().isCreated());
assertThat(taskRepository.existsByTitle("Stored Task")).isTrue();
}
}
The test checks both API behavior and database state.
Memory sentence:
Full integration tests can verify external response and internal database state.
13. Test Transactions and Rollback
Spring tests can be transactional.
Example:
@SpringBootTest
@Transactional
class TaskIntegrationTest {
}
By default, transactional test methods roll back after the test.
Meaning:
test creates data
test verifies behavior
test finishes
transaction rolls back
database is clean again
Memory sentence:
Transactional tests commonly roll back after each test.
14. Important Transaction Trap with MockMvc
If the test method is @Transactional, but the request is handled in another thread or real server mode, rollback behavior can be different.
For MockMvc with mock servlet environment, rollback is usually simpler.
For real HTTP with RANDOM_PORT, server request handling may use a different transaction from the test method.
So this pattern can be tricky:
@SpringBootTest(webEnvironment = RANDOM_PORT)
@Transactional
class RealHttpTest {
}
Memory sentence:
Rollback behavior is easier with repository tests and MockMvc than with real-server tests.
15. Clean Database Strategies
For integration tests, database cleanup matters.
Options:
transaction rollback
delete data before each test
delete data after each test
use fresh Testcontainer
use @Sql cleanup scripts
use database cleaner utility
Good rule:
Each test should be independent.
Memory sentence:
Integration tests need a clear database cleanup strategy.
16. @Sql in Integration Tests
Example:
@SpringBootTest
@AutoConfigureMockMvc
@Sql("/sql/clean.sql")
@Sql("/sql/test-data.sql")
class TaskApiIntegrationTest {
}
Example cleanup:
delete from tasks;
delete from clients;
Useful when:
test data is complex
many tests need same setup
database must be cleaned explicitly
Memory sentence:
@Sqlcan prepare or clean database state for integration tests.
17. Testcontainers for Integration Tests
Testcontainers can start a real database in Docker.
Example:
PostgreSQL container
Redis container
Kafka container
RabbitMQ container
LocalStack container
Why useful?
real infrastructure behavior
production-like database
isolated test environment
works in CI
less local setup
native SQL is tested realistically
Memory sentence:
Testcontainers gives production-like infrastructure for tests.
18. PostgreSQL Testcontainers Example
Dependencies:
testImplementation("org.testcontainers:junit-jupiter")
testImplementation("org.testcontainers:postgresql")
testImplementation("org.springframework.boot:spring-boot-testcontainers")
Test:
@SpringBootTest
@AutoConfigureMockMvc
@Testcontainers
class TaskApiPostgresIntegrationTest {
@Container
@ServiceConnection
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16");
@Autowired
private MockMvc mockMvc;
@Test
void createsTaskUsingRealPostgres() throws Exception {
mockMvc.perform(post("/api/tasks")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"title": "Postgres Task"
}
"""))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.title").value("Postgres Task"));
}
}
Important:
This needs Docker.
Memory sentence:
Use Testcontainers when database realism matters.
19. Testcontainers Without @ServiceConnection
Older/manual style:
@SpringBootTest
@Testcontainers
class TaskApiPostgresIntegrationTest {
@Container
static PostgreSQLContainer<?> postgres =
new PostgreSQLContainer<>("postgres:16");
@DynamicPropertySource
static void configureDatasource(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
}
Memory sentence:
DynamicPropertySourceconnects container properties to Spring.
20. Testing External Services
Do not call real external services in normal automated tests.
Bad:
send real email
call real payment provider
upload to production S3
call real third-party API
Better:
mock the client
use fake server
use sandbox environment carefully
use Testcontainers where possible
Memory sentence:
Integration tests should be realistic but safe.
21. Mocking External Beans in @SpringBootTest
Example:
@SpringBootTest
class OrderIntegrationTest {
@MockitoBean
private PaymentClient paymentClient;
@Autowired
private OrderService orderService;
@Test
void createsOrderWhenPaymentSucceeds() {
when(paymentClient.charge(any()))
.thenReturn(new PaymentResult("OK"));
orderService.createOrder(...);
verify(paymentClient).charge(any());
}
}
Older projects may use:
@MockBean
Memory sentence:
In integration tests, mock unsafe external systems.
22. Testing Application Properties
Configuration properties:
@ConfigurationProperties(prefix = "app.storage")
public class StorageProperties {
private String bucket;
private int maxFileSizeMb;
// getters and setters
}
Test:
@SpringBootTest(properties = {
"app.storage.bucket=test-bucket",
"app.storage.max-file-size-mb=10"
})
class StoragePropertiesTest {
@Autowired
private StorageProperties properties;
@Test
void bindsStorageProperties() {
assertThat(properties.getBucket()).isEqualTo("test-bucket");
assertThat(properties.getMaxFileSizeMb()).isEqualTo(10);
}
}
Memory sentence:
Integration tests can verify configuration binding.
23. Testing Profiles
Example:
@SpringBootTest
@ActiveProfiles("test")
class ApplicationTest {
}
This loads:
application-test.yml
Useful for:
test database
disabled email sending
fake API URLs
test feature flags
smaller connection pools
Memory sentence:
Use test profile for test-specific configuration.
24. Testing Security in Integration Tests
Example:
@SpringBootTest
@AutoConfigureMockMvc
class SecurityIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void anonymousCannotAccessTasks() throws Exception {
mockMvc.perform(get("/api/tasks"))
.andExpect(status().isUnauthorized());
}
@Test
@WithMockUser(authorities = "TASK_READ")
void userWithReadAuthorityCanAccessTasks() throws Exception {
mockMvc.perform(get("/api/tasks"))
.andExpect(status().isOk());
}
}
This checks real security configuration plus MVC flow.
Memory sentence:
Integration tests can verify real security rules.
25. Testing CSRF in Integration Tests
If CSRF is enabled:
@Test
@WithMockUser(authorities = "TASK_WRITE")
void postWithoutCsrfIsForbidden() throws Exception {
mockMvc.perform(post("/api/tasks")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"title":"Task A"}
"""))
.andExpect(status().isForbidden());
}
With CSRF:
@Test
@WithMockUser(authorities = "TASK_WRITE")
void postWithCsrfIsAllowed() throws Exception {
mockMvc.perform(post("/api/tasks")
.with(csrf())
.contentType(MediaType.APPLICATION_JSON)
.content("""
{"title":"Task A"}
"""))
.andExpect(status().isCreated());
}
Memory sentence:
If CSRF is enabled, unsafe methods need CSRF even in integration tests.
26. Testing JWT Integration
For resource server tests:
@Test
void jwtWithReadScopeCanAccessTasks() throws Exception {
mockMvc.perform(get("/api/tasks")
.with(jwt().authorities(
new SimpleGrantedAuthority("SCOPE_task:read")
)))
.andExpect(status().isOk());
}
This avoids generating a real JWT.
It tests:
Spring Security authorization using mocked JWT authentication
Memory sentence:
Use
jwt()to test resource-server authorization rules.
27. What Is Enough for Spring Professional Exam?
For the exam, focus on understanding concepts, not memorizing every tool detail.
You should know:
unit test vs integration test
test pyramid
JUnit role
AssertJ role
Mockito role
@MockBean / @MockitoBean role
@SpringBootTest
@WebMvcTest
@DataJpaTest
MockMvc
TestEntityManager
test slices
test profiles
test properties
transaction rollback
@DirtiesContext
security testing basics
CSRF in tests
when to use Testcontainers
Memory sentence:
For the exam, know when and why to use each test type.
28. Testing Decision Table for Exam
| Need to test | Best choice |
|---|---|
| Pure business logic | unit test |
| Service with mocked repository | unit test + Mockito |
| Controller request/response | @WebMvcTest + MockMvc |
| Validation returns 400 | @WebMvcTest |
Error response from @ControllerAdvice | @WebMvcTest |
| Repository query | @DataJpaTest |
| Entity relationship mapping | @DataJpaTest |
| Database constraint | @DataJpaTest + flush() |
| Full app context starts | @SpringBootTest |
| Controller + Service + Repository | @SpringBootTest + MockMvc |
| Real HTTP server | @SpringBootTest(RANDOM_PORT) |
| PostgreSQL-specific SQL | Testcontainers PostgreSQL |
| Security endpoint rule | MockMvc + spring-security-test |
| Method security | Spring test + @WithMockUser |
Memory sentence:
Pick the smallest test that proves the behavior.
29. Final Testing Mock Exam
Question 1
What is a unit test?
A. Test one class without Spring B. Test full application context C. Test only database schema D. Test production server manually
Answer:
A
Question 2
What does @SpringBootTest do?
A. Loads full Spring Boot application context B. Loads only JPA repositories C. Loads only one controller D. Disables Spring
Answer:
A
Question 3
What does @WebMvcTest test?
A. MVC/controller slice B. Full database only C. Kafka only D. Flyway only
Answer:
A
Question 4
What does @DataJpaTest test?
A. JPA entities and repositories B. REST controllers only C. Security filters only D. External APIs only
Answer:
A
Question 5
What is MockMvc used for?
A. Testing MVC requests without real server B. Starting PostgreSQL C. Creating JWT signatures D. Running Flyway manually
Answer:
A
Question 6
What is TestEntityManager used for?
A. Helping persist, flush, clear, and find entities in JPA tests B. Testing CSS C. Creating mock HTTP users D. Running REST calls
Answer:
A
Question 7
Why use flush() in a repository test?
A. To force SQL/database constraint execution B. To disable Spring Security C. To create a mock D. To start web server
Answer:
A
Question 8
Why use clear() in a repository test?
A. To avoid reading only from persistence context cache B. To delete the application context C. To disable JPA D. To remove HTTP headers
Answer:
A
Question 9
What does @MockBean or @MockitoBean do?
A. Replaces a Spring bean with a Mockito mock B. Creates a database table C. Starts a Docker container D. Enables transactions
Answer:
A
Question 10
What is Testcontainers useful for?
A. Running real infrastructure like PostgreSQL in Docker during tests B. Mocking Java methods only C. Creating REST controllers D. Disabling tests
Answer:
A
Question 11
What is the default rollback behavior for transactional Spring tests?
A. Rollback by default B. Commit by default always C. Delete application context D. Disable repositories
Answer:
A
Question 12
What is @DirtiesContext used for?
A. Telling Spring not to reuse the test context B. Cleaning database rows only C. Creating JSON D. Mocking controllers
Answer:
A
Question 13
When should I use @SpringBootTest instead of @WebMvcTest?
A. When I need multiple layers or full app context B. When I only test request validation C. When I only test one pure Java method D. Never
Answer:
A
Question 14
When should I use @DataJpaTest?
A. To test repository queries and entity mappings B. To test React components C. To test controller JSON only D. To test external email provider
Answer:
A
Question 15
What is the best test for pure calculation logic?
A. Unit test
B. @SpringBootTest
C. @DataJpaTest
D. Real HTTP test
Answer:
A
Question 16
What is the best test for controller validation?
A. @WebMvcTest
B. @DataJpaTest
C. Manual database test
D. Testcontainers only
Answer:
A
Question 17
What is the best test for custom repository query?
A. @DataJpaTest
B. Plain unit test with mocked repository
C. CSS test
D. Controller test only
Answer:
A
Question 18
What is the best test for full controller-service-repository flow?
A. @SpringBootTest
B. Plain unit test only
C. @JsonTest only
D. No test
Answer:
A
Question 19
What does .with(csrf()) do?
A. Adds CSRF token to MockMvc request B. Adds JWT claim C. Starts database D. Disables validation
Answer:
A
Question 20
What does @WithMockUser do?
A. Adds mocked authenticated user to security context B. Creates real database user C. Starts real browser D. Disables security
Answer:
A
30. Final Exam Traps
Trap 1
Do not use @SpringBootTest for every test.
Use smaller tests when possible.
Trap 2
@WebMvcTest does not test real service/database behavior.
It tests the web layer.
Trap 3
@DataJpaTest does not test controllers.
It tests JPA.
Trap 4
Mocking a repository does not prove repository SQL works.
It only helps test service logic.
Trap 5
@MockBean / @MockitoBean is for Spring tests.
Plain unit tests use Mockito mock() or @Mock.
Trap 6
POST/PUT/PATCH/DELETE tests may need CSRF.
Trap 7
Validation needs @Valid.
Trap 8
Repository constraint tests often need flush().
Trap 9
Repository tests may need clear() to avoid cached entities.
Trap 10
H2 is not always the same as PostgreSQL.
Trap 11
Testcontainers is useful when database realism matters.
Trap 12
@DirtiesContext can slow the test suite.
Trap 13
Integration tests need a cleanup strategy.
Trap 14
Do not call real external production services in automated tests.
Trap 15
Choose the smallest test that proves the behavior.
31. Final Testing Checklist for Spring Professional Exam
I am ready for testing questions if I can explain:
[ ] What a unit test is.
[ ] Why unit tests should not start Spring.
[ ] What JUnit does.
[ ] What AssertJ does.
[ ] What Mockito does.
[ ] What mocks and stubs are.
[ ] What @MockBean / @MockitoBean does.
[ ] What @SpringBootTest does.
[ ] What @WebMvcTest does.
[ ] What @DataJpaTest does.
[ ] What MockMvc does.
[ ] What TestEntityManager does.
[ ] Why flush() is useful.
[ ] Why clear() is useful.
[ ] What test slices are.
[ ] When to use slice tests.
[ ] When to use full integration tests.
[ ] What test profiles are.
[ ] What test properties are.
[ ] What @DirtiesContext does.
[ ] How transactional rollback works in tests.
[ ] How to test controller validation.
[ ] How to test repository queries.
[ ] How to test secured endpoints.
[ ] Why POST tests may need csrf().
[ ] What Testcontainers is.
[ ] Why H2 can differ from PostgreSQL.
[ ] Why tests should be independent.
[ ] Why tests should be deterministic.
[ ] How to choose the smallest useful test.
32. Final Summary
Testing in Spring Boot has several levels.
The main levels are:
unit tests
web slice tests
JPA slice tests
integration tests
The main rule is:
Choose the smallest test that proves the behavior.
For service logic:
Use unit tests with JUnit, AssertJ, and Mockito.
For controllers:
Use @WebMvcTest and MockMvc.
For repositories:
Use @DataJpaTest and TestEntityManager.
For full application behavior:
Use @SpringBootTest.
For real database behavior:
Use Testcontainers when H2 is not realistic enough.
For exam memory:
Unit test = one class, no Spring.
WebMvcTest = controller slice.
DataJpaTest = repository slice.
SpringBootTest = full application context.
MockMvc = HTTP-like MVC test without real server.
Testcontainers = real infrastructure in Docker.
This is enough testing knowledge for a strong Spring Professional exam preparation foundation.