Skip to main content

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:

  1. What is an integration test?
  2. What does @SpringBootTest do?
  3. When should I use @SpringBootTest?
  4. What is the difference between @SpringBootTest and slice tests?
  5. How do I test full web flows with MockMvc?
  6. How do I test with a real HTTP port?
  7. How do I test with Testcontainers?
  8. How do transactions and rollback work in tests?
  9. What testing knowledge is enough for Spring Professional exam?
  10. 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.
  • @WebMvcTest tests the MVC/controller slice.
  • @DataJpaTest tests the JPA/repository slice.
  • @SpringBootTest loads the full Spring Boot application context.
  • MockMvc tests HTTP behavior without a real server.
  • TestEntityManager helps in JPA tests.
  • spring-security-test helps 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:

@SpringBootTest starts 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:

contextLoads checks 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 @SpringBootTest only when the test needs the full app.


6. @SpringBootTest vs Slice Tests

TestScopeGood for
Unit testone class, no Springbusiness logic
@WebMvcTestMVC slicecontrollers, validation, JSON
@DataJpaTestJPA slicerepositories, mappings, queries
@SpringBootTestfull app contextintegration 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 + MockMvc tests 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:

ModeMeaning
MOCKmock servlet environment, no real server
RANDOM_PORTstarts real server on random port
DEFINED_PORTstarts real server on configured port
NONEno web environment

Memory sentence:

MOCK is common with MockMvc; RANDOM_PORT starts 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_PORT when I want real HTTP.


11. MockMvc vs TestRestTemplate

ToolServer?Good for
MockMvcno real serverMVC integration tests
TestRestTemplatereal serverreal 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:

@Sql can 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:

DynamicPropertySource connects 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 testBest choice
Pure business logicunit test
Service with mocked repositoryunit 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 SQLTestcontainers PostgreSQL
Security endpoint ruleMockMvc + spring-security-test
Method securitySpring 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.