Skip to main content

Week 7 Day 1 — Spring Boot Testing Mental Model

Goal

Today I want to understand the big picture of testing in Spring Boot.

Main questions:

  1. Why do we write tests?
  2. What is the test pyramid?
  3. What is a unit test?
  4. What is a slice test?
  5. What is an integration test?
  6. What is the Spring TestContext?
  7. Why are Spring tests slower than pure unit tests?
  8. What does @SpringBootTest do?
  9. What are test slices like @WebMvcTest and @DataJpaTest?
  10. When should I use mocks?
  11. When should I use the real Spring context?
  12. What are common exam traps?

1. Quick Review from Week 6

In Week 6, I learned:

  • Spring Security protects requests before controllers.
  • Authentication means proving identity.
  • Authorization means checking permissions.
  • 401 means not authenticated.
  • 403 means authenticated but not allowed.
  • SecurityFilterChain defines security rules.
  • UserDetailsService loads users.
  • PasswordEncoder hashes passwords.
  • @PreAuthorize protects methods.
  • CSRF and CORS are different.
  • Security tests should test allowed and denied cases.

Memory sentence:

Security tests prove that allowed users are allowed and forbidden users are blocked.

Now I move to a bigger topic:

How do I test a Spring Boot application well?

2. Why Do We Write Tests?

Tests help answer:

Does my code work?
Does it still work after changes?
Did I break an old feature?
Does my controller return the right response?
Does my service follow business rules?
Does my repository query the database correctly?
Does security block the wrong users?
Does validation reject invalid input?

Tests are not only for checking code.

They are also documentation.

A good test says:

This is how the application should behave.

Memory sentence:

Tests protect behavior.


3. What Should We Test?

In a Spring Boot app, I often test:

business logic
controllers
request validation
exception handling
repositories
database queries
transactions
security rules
JSON serialization
external API clients
configuration
full application flow

But I should not test everything in the same way.

Some things need small fast tests.

Some things need Spring context.

Some things need a real database.

Memory sentence:

Different problems need different test types.


4. The Test Pyramid

The test pyramid is a mental model.

E2E Tests
/ \
/ Integration \
/ Tests \
/ \
/ Slice Tests \
/ \
/ Unit Tests \
/_________________________\

Meaning:

many unit tests
some slice/integration tests
few end-to-end tests

Why?

unit tests are fast
integration tests are slower
end-to-end tests are slowest and more fragile

Memory sentence:

Have many fast tests and fewer slow full-system tests.


5. Main Test Types

Test typeWhat it testsSpring context?Speed
Unit testone class/methodnovery fast
Slice testone Spring layerpartialmedium
Integration testmultiple layers/full appyesslower
End-to-end testreal user flowoften full systemslowest

Memory sentence:

Unit tests are small. Integration tests are realistic.


6. Unit Test

A unit test tests one small piece of code.

Usually:

no Spring context
no database
no web server
no real HTTP
no real external API

Example target:

TaskService business logic
PriceCalculator
PermissionService
Validator helper
Mapper

Memory sentence:

A unit test tests one unit without starting Spring.


7. Unit Test Example

Service:

public class TaskTitlePolicy {

public void validate(String title) {
if (title == null || title.isBlank()) {
throw new IllegalArgumentException("Title must not be blank");
}

if (title.length() > 100) {
throw new IllegalArgumentException("Title is too long");
}
}
}

Unit test:

class TaskTitlePolicyTest {

private final TaskTitlePolicy policy = new TaskTitlePolicy();

@Test
void rejectsBlankTitle() {
assertThatThrownBy(() -> policy.validate(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Title must not be blank");
}

@Test
void acceptsValidTitle() {
policy.validate("Prepare tax documents");
}
}

No Spring.

No database.

Very fast.

Memory sentence:

If I can test without Spring, test without Spring.


8. Unit Test with Mockito

Service:

public class TaskService {

private final TaskRepository taskRepository;

public TaskService(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}

public TaskDto findById(Long id) {
TaskEntity task = taskRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Task", id));

return new TaskDto(task.getId(), task.getTitle(), task.getStatus());
}
}

Unit test:

class TaskServiceTest {

private final TaskRepository taskRepository = mock(TaskRepository.class);

private final TaskService taskService = new TaskService(taskRepository);

@Test
void returnsTaskById() {
TaskEntity task = new TaskEntity(1L, "Learn tests", "OPEN");

when(taskRepository.findById(1L))
.thenReturn(Optional.of(task));

TaskDto result = taskService.findById(1L);

assertThat(result.id()).isEqualTo(1L);
assertThat(result.title()).isEqualTo("Learn tests");
assertThat(result.status()).isEqualTo("OPEN");
}
}

This test checks service behavior.

It does not check if the repository query really works.

Memory sentence:

Mock dependencies when testing one class in isolation.


9. What Unit Tests Are Good For

Unit tests are good for:

business rules
if/else logic
calculations
mapping logic
permission logic
validation helper logic
error behavior
edge cases

Examples:

Can user access task?
Is invoice overdue?
Can task be completed?
Is password strong enough?
Should notification be sent?

Memory sentence:

Unit tests are best for business logic and edge cases.


10. What Unit Tests Are Not Good For

Unit tests are not enough for:

JPA mapping
real SQL queries
Spring MVC request mapping
Jackson JSON conversion
Bean Validation integration
Spring Security filter chain
transaction behavior
real application configuration

For these, I need Spring tests.

Memory sentence:

Unit tests do not prove Spring wiring or framework integration.


11. Slice Test

A slice test loads only part of the Spring application.

Examples:

@WebMvcTest
@DataJpaTest
@JsonTest
@RestClientTest

Slice tests are faster than full integration tests because they do not load the whole application.

They test one layer or one technical slice.

Memory sentence:

A slice test loads only the part of Spring needed for that layer.


12. Common Slice Tests

AnnotationTests
@WebMvcTestcontrollers, MVC, validation, JSON, MockMvc
@DataJpaTestJPA entities, repositories, queries
@JsonTestJSON serialization/deserialization
@RestClientTestREST clients
@JdbcTestJDBC components

Memory sentence:

Slice annotations focus the Spring context.


13. @WebMvcTest

@WebMvcTest is for testing the web layer.

It commonly tests:

controller request mapping
request parameters
request body JSON
validation
HTTP status
response JSON
controller exception handling
security rules if included

Example:

@WebMvcTest(TaskController.class)
class TaskControllerTest {

@Autowired
private MockMvc mockMvc;

@MockBean
private TaskService taskService;

@Test
void returnsTask() throws Exception {
when(taskService.findById(1L))
.thenReturn(new TaskDto(1L, "Learn MVC test", "OPEN"));

mockMvc.perform(get("/api/tasks/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.title").value("Learn MVC test"));
}
}

Important:

The service is mocked.
The controller is tested.

Memory sentence:

@WebMvcTest tests the controller layer, not the real service/database.


14. @DataJpaTest

@DataJpaTest is for testing JPA persistence.

It commonly tests:

entity mapping
repository methods
derived queries
@Query methods
relationships
constraints
pagination
sorting
database behavior

Example:

@DataJpaTest
class TaskRepositoryTest {

@Autowired
private TaskRepository taskRepository;

@Autowired
private TestEntityManager entityManager;

@Test
void findsByStatus() {
entityManager.persist(new TaskEntity("Task A", "OPEN"));
entityManager.persist(new TaskEntity("Task B", "DONE"));
entityManager.flush();

List<TaskEntity> result = taskRepository.findByStatus("OPEN");

assertThat(result)
.extracting(TaskEntity::getTitle)
.containsExactly("Task A");
}
}

Memory sentence:

@DataJpaTest tests repositories and JPA mapping.


15. Slice Test Mental Model

A slice test asks:

Does this Spring layer work correctly?

Examples:

Does controller parse JSON correctly?
Does validation return 400?
Does exception handler return error response?
Does repository query return the right rows?
Does Jackson serialize this DTO correctly?

It does not ask:

Does the whole application work end-to-end?

Memory sentence:

Slice tests are focused Spring tests.


16. Integration Test

An integration test checks multiple parts working together.

Example:

Controller + Service + Repository + Database

or:

Security + Controller + Service

or:

Application context + configuration + external client mock

Integration tests often use:

@SpringBootTest

Memory sentence:

Integration tests prove that multiple parts work together.


17. @SpringBootTest

@SpringBootTest loads the full Spring Boot application context.

Example:

@SpringBootTest
class ApplicationContextTest {

@Test
void contextLoads() {
}
}

This checks:

Can the application context start?
Are beans configured correctly?
Are dependencies wired correctly?
Is configuration valid?

But it can be slower.

Memory sentence:

@SpringBootTest starts the full application context.


18. @SpringBootTest with MockMvc

Example:

@SpringBootTest
@AutoConfigureMockMvc
class TaskApiIntegrationTest {

@Autowired
private MockMvc mockMvc;

@Test
void getsTask() throws Exception {
mockMvc.perform(get("/api/tasks/1"))
.andExpect(status().isOk());
}
}

This can test:

full application context
security filters
controllers
services
repositories
database
exception handling
JSON conversion

Memory sentence:

@SpringBootTest + MockMvc tests web flow without starting a real server.


19. @SpringBootTest Web Environment

@SpringBootTest can use different web environments.

Common options:

@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.


20. Integration Test with Real HTTP

Example:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class TaskApiRealHttpTest {

@Autowired
private TestRestTemplate restTemplate;

@Test
void getsHealth() {
ResponseEntity<String> response =
restTemplate.getForEntity("/actuator/health", String.class);

assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}

This starts a real embedded server.

Useful when I want to test:

real HTTP layer
server port
filters
serialization
full request/response behavior

Memory sentence:

RANDOM_PORT tests through real HTTP.


21. What Is Spring TestContext?

Spring TestContext is the testing framework support that manages Spring application contexts in tests.

It helps with:

loading application context
dependency injection into tests
transaction management in tests
test properties
active profiles
context caching
DirtiesContext
integration with JUnit

Example:

@SpringBootTest
class TaskServiceIntegrationTest {

@Autowired
private TaskService taskService;
}

Spring injects beans into the test because the TestContext framework is active.

Memory sentence:

Spring TestContext manages Spring application contexts for tests.


22. Why Are Spring Tests Slower?

Spring tests can be slower because they may:

start application context
create many beans
load auto-configuration
connect to database
start embedded web environment
initialize security filters
run migrations
scan classpath

Unit tests avoid all this.

Memory sentence:

Starting Spring costs time; use it only when the test needs Spring.


23. Context Caching

Spring can cache application contexts between tests.

If two tests use the same context configuration, Spring can reuse the context.

This makes tests faster.

But if I change the context with:

@DirtiesContext

then Spring may close and rebuild the context.

Memory sentence:

Spring caches test contexts; do not dirty the context unnecessarily.


24. @DirtiesContext

@DirtiesContext tells Spring:

This test changed the context; do not reuse it.

Example use case:

test changes global bean state
test modifies application context
test changes environment in a way that affects future tests

But it slows down the test suite.

Memory sentence:

Use @DirtiesContext rarely.


25. Test Profiles

Tests often use a special profile.

Example:

@ActiveProfiles("test")
@SpringBootTest
class TaskServiceIntegrationTest {
}

Then Spring can load:

application-test.yml

Example:

spring:
datasource:
url: jdbc:postgresql://localhost:5432/test_db

Memory sentence:

Use test profile for test-specific configuration.


26. Test Properties

Inline properties:

@SpringBootTest(properties = {
"feature.email.enabled=false",
"app.security.demo-mode=true"
})
class AppTest {
}

This overrides properties for the test.

Useful for:

disable external integrations
change feature flags
use fake URLs
configure test behavior

Memory sentence:

Test properties customize the application context for tests.


27. @MockBean

@MockBean replaces a Spring bean with a Mockito mock in the application context.

Example:

@WebMvcTest(TaskController.class)
class TaskControllerTest {

@MockBean
private TaskService taskService;
}

Meaning:

When controller needs TaskService, Spring injects the mock.

Useful for slice tests.

Memory sentence:

@MockBean mocks a Spring bean inside the test context.


28. Mockito mock() vs @MockBean

ToolWhere it works
mock()plain unit test
@MockMockito test
@MockBeanSpring test context

Example plain unit test:

TaskRepository repository = mock(TaskRepository.class);
TaskService service = new TaskService(repository);

Example Spring test:

@MockBean
TaskService taskService;

Memory sentence:

Use mock() for unit tests; use @MockBean when Spring must inject the mock.


29. @SpyBean

@SpyBean wraps a real Spring bean with a Mockito spy.

It can call real methods but still allow verification/stubbing.

Use carefully.

Example:

@SpyBean
private EmailService emailService;

Then:

verify(emailService).sendWelcomeEmail(any());

But too much spying can make tests fragile.

Memory sentence:

@SpyBean observes a real Spring bean, but use it carefully.


30. Test Data

Tests need data.

Options:

create data in test code
use SQL scripts
use TestEntityManager
use repositories
use fixtures/builders
use migrations with clean database

Good practice:

Make test data clear and close to the test.

Example:

TaskEntity task = new TaskEntity("Task A", "OPEN");
entityManager.persistAndFlush(task);

Memory sentence:

Clear test data makes tests easier to understand.


31. Arrange, Act, Assert

A common test structure:

Arrange
Act
Assert

Example:

@Test
void completesTask() {
// Arrange
TaskEntity task = new TaskEntity("Task A", "OPEN");
when(taskRepository.findById(1L)).thenReturn(Optional.of(task));

// Act
TaskDto result = taskService.complete(1L);

// Assert
assertThat(result.status()).isEqualTo("DONE");
}

Memory sentence:

Arrange data, act once, assert result.


32. Given, When, Then

Another naming style:

given
when
then

Example:

@Test
void givenOpenTask_whenComplete_thenStatusIsDone() {
}

Or simpler:

@Test
void completesOpenTask() {
}

Good test names explain behavior.

Memory sentence:

Test names should describe behavior.


33. What Makes a Good Test?

A good test is:

clear
fast enough
repeatable
independent
focused
deterministic
easy to debug
close to business behavior

Bad test:

depends on test order
depends on current time randomly
depends on external API
has unclear data
tests many things at once
requires manual setup

Memory sentence:

Good tests are repeatable and easy to understand.


34. Independent Tests

Each test should be independent.

Bad:

Test B only passes if Test A runs first.

Good:

Each test creates its own data.
Each test can run alone.

Memory sentence:

Tests should not depend on execution order.


35. Deterministic Tests

A deterministic test gives the same result every time.

Bad causes:

random data without control
real current time
external network calls
shared mutable state
test order dependency
real email sending
real payment API

Better:

use fixed Clock
mock external APIs
create isolated data
use test containers or test database

Memory sentence:

A test should not sometimes pass and sometimes fail.


36. Testing Time

Bad service:

public boolean isOverdue(TaskEntity task) {
return task.getDueDate().isBefore(LocalDate.now());
}

Harder to test because current date changes.

Better:

public class TaskDeadlineService {

private final Clock clock;

public TaskDeadlineService(Clock clock) {
this.clock = clock;
}

public boolean isOverdue(TaskEntity task) {
LocalDate today = LocalDate.now(clock);
return task.getDueDate().isBefore(today);
}
}

Test:

Clock fixedClock = Clock.fixed(
Instant.parse("2026-07-07T10:00:00Z"),
ZoneOffset.UTC
);

Memory sentence:

Inject Clock instead of calling current time directly in business logic.


37. Testing External APIs

Do not call real external APIs in normal automated tests.

Bad:

test calls real payment provider
test sends real email
test uploads to real S3 bucket
test calls production API

Better:

mock external client in unit/slice tests
use fake server in integration tests
use test environment/sandbox carefully

Memory sentence:

Automated tests should not depend on real external services.


38. Test Database Choices

Common options:

H2/in-memory database
local PostgreSQL test database
Testcontainers PostgreSQL
mock repository

Use based on test type.

OptionGood for
Mock repositoryservice unit tests
H2fast simple repository tests
Testcontainersproduction-like database tests
Local test DBlocal integration testing

Memory sentence:

Mock repositories for service logic; real database for repository behavior.


39. H2 vs PostgreSQL

H2 is fast and simple.

But it may behave differently from PostgreSQL.

Differences can include:

SQL syntax
JSON columns
case sensitivity
indexes
constraints
date/time behavior
native queries
locking behavior
migration scripts

For important persistence tests, use the same database type as production.

Memory sentence:

H2 is fast, but production-like database tests catch production-like bugs.


40. Testcontainers Preview

Testcontainers can start real services in Docker during tests.

Example services:

PostgreSQL
Redis
Kafka
RabbitMQ
LocalStack

For Spring Boot database tests, Testcontainers can provide a real PostgreSQL database.

We will study this later.

Memory sentence:

Testcontainers gives real infrastructure for integration tests.


41. Which Test Type Should I Choose?

Ask:

What do I want to prove?

If I want to prove business logic:

unit test

If I want to prove controller mapping and validation:

@WebMvcTest

If I want to prove repository query:

@DataJpaTest

If I want to prove full flow:

@SpringBootTest

If I want to prove real database behavior:

@DataJpaTest or @SpringBootTest with real DB/Testcontainers

Memory sentence:

Choose the smallest test that proves the behavior.


42. Example: Testing Create Task

Feature:

POST /api/tasks creates a task.

Possible tests:

Unit Test

Test service business logic:

given valid request
when create task
then repository save is called
then DTO is returned

Web Slice Test

Test controller:

given JSON request
when POST /api/tasks
then status 201
then validation errors return 400

Repository Test

Test repository:

given saved task
when findByStatus
then task is returned

Integration Test

Test full flow:

given request
when POST /api/tasks
then controller, service, repository, database work together

Memory sentence:

One feature can have different tests at different levels.


43. What Not to Over-Test

Avoid tests that only test the framework.

Bad:

@Test
void repositorySaveWorks() {
TaskEntity saved = taskRepository.save(new TaskEntity("A", "OPEN"));
assertThat(saved.getId()).isNotNull();
}

This mostly tests Spring Data/Hibernate.

Better:

test custom query
test mapping constraint
test relationship
test business behavior
test validation

Memory sentence:

Test your code and configuration, not Spring itself.


44. Common Exam Traps

Trap 1

Unit tests do not need Spring context.


Trap 2

@SpringBootTest loads the full application context.


Trap 3

Full context tests are slower than unit tests.


Trap 4

Slice tests load only part of the application.


Trap 5

@WebMvcTest tests web layer, not real service/database.


Trap 6

@DataJpaTest tests JPA repositories/entities, not controllers.


Trap 7

@MockBean replaces a Spring bean in the test context.


Trap 8

Mockito mock() is for plain unit tests.


Trap 9

Spring TestContext can cache contexts.


Trap 10

@DirtiesContext can make tests slower.


Trap 11

Use @ActiveProfiles("test") for test configuration.


Trap 12

H2 may behave differently from PostgreSQL.


Trap 13

Do not call real external APIs in automated tests.


Trap 14

Tests should be independent and deterministic.


Trap 15

Choose the smallest test that proves the behavior.


45. Real Exam Question: Unit Test

Question:

What is a unit test?

Answer:

A unit test tests a small piece of code, usually one class or method, without starting the Spring context or real infrastructure.


46. Real Exam Question: Slice Test

Question:

What is a slice test?

Answer:

A slice test loads only a specific part of the Spring application context, such as the web layer or JPA layer.


47. Real Exam Question: Integration Test

Question:

What is an integration test?

Answer:

An integration test checks multiple parts of the application working together, often with a Spring application context.


48. Real Exam Question: @SpringBootTest

Question:

What does @SpringBootTest do?

Answer:

@SpringBootTest loads the full Spring Boot application context for integration testing.


49. Real Exam Question: @WebMvcTest

Question:

What does @WebMvcTest test?

Answer:

@WebMvcTest tests the web/MVC layer, such as controllers, request mapping, validation, JSON responses, and controller advice. Service dependencies are often mocked.


50. Real Exam Question: @DataJpaTest

Question:

What does @DataJpaTest test?

Answer:

@DataJpaTest tests JPA components such as entities, repositories, mappings, and queries.


51. Real Exam Question: @MockBean

Question:

What does @MockBean do?

Answer:

@MockBean replaces a Spring bean in the application context with a Mockito mock.


52. Real Exam Question: TestContext

Question:

What does the Spring TestContext framework do?

Answer:

It manages Spring application contexts for tests, supports dependency injection into tests, test properties, profiles, transactions, and context caching.


53. Interview Answer

Question:

Explain the difference between unit tests, slice tests, and integration tests.

Good answer:

A unit test tests a small piece of code without starting Spring, usually with mocks for dependencies. A slice test starts only part of the Spring context, such as the MVC layer with @WebMvcTest or the JPA layer with @DataJpaTest. An integration test uses a larger or full Spring context, often with @SpringBootTest, to verify that multiple parts of the application work together.


54. Interview Answer

Question:

When would you use @SpringBootTest?

Good answer:

I use @SpringBootTest when I need the full application context or want to test multiple layers together, such as controller, service, repository, security configuration, and database integration. I avoid using it for every test because it is slower than unit or slice tests.


55. Interview Answer

Question:

When would you use @WebMvcTest?

Good answer:

I use @WebMvcTest to test the controller layer. It is good for request mapping, request body handling, validation, response status, JSON response, and controller exception handling. I usually mock service dependencies with @MockBean.


56. Interview Answer

Question:

When would you use @DataJpaTest?

Good answer:

I use @DataJpaTest to test repository queries, JPA mappings, entity relationships, constraints, pagination, and sorting. It focuses on the persistence layer and does not load controllers or normal service beans.


57. Interview Answer

Question:

How do you decide which test type to write?

Good answer:

I ask what behavior I want to prove. If it is pure business logic, I write a unit test. If it is controller behavior, I use @WebMvcTest. If it is repository behavior, I use @DataJpaTest. If I need multiple layers working together, I use @SpringBootTest. I choose the smallest test that proves the behavior.


58. Tiny Code Practice

Question:

For each situation, choose the best test type.

Situation 1

I want to test this method:

public int calculateDiscount(int price, int percent) {
return price * percent / 100;
}

Best test type:

Unit test

Why?

No Spring needed.

Situation 2

I want to test that invalid JSON returns 400 from a controller.

Best test type:

@WebMvcTest

Why?

This is web/controller behavior.

Situation 3

I want to test that findByEmail works.

Best test type:

@DataJpaTest

Why?

This is repository/database behavior.

Situation 4

I want to test login + security + controller + database together.

Best test type:

@SpringBootTest

Why?

Multiple application layers must work together.

59. Tiny Bug Practice 1

Problem:

@SpringBootTest
class PriceCalculatorTest {

@Autowired
private PriceCalculator priceCalculator;

@Test
void calculatesDiscount() {
assertThat(priceCalculator.calculateDiscount(100, 10)).isEqualTo(10);
}
}

Question:

What is the issue?

Answer:

This is pure calculation logic. Starting the full Spring context is unnecessary. Use a plain unit test.


60. Tiny Bug Practice 2

Problem:

@WebMvcTest(TaskController.class)
class TaskControllerTest {

@Autowired
private MockMvc mockMvc;

@Test
void returnsTask() throws Exception {
mockMvc.perform(get("/api/tasks/1"))
.andExpect(status().isOk());
}
}

But the controller depends on TaskService, and the test fails to start.

Question:

What is missing?

Answer:

A mock service bean is missing.

@MockBean
private TaskService taskService;

61. Tiny Bug Practice 3

Problem:

@DataJpaTest
class TaskServiceTest {

@Autowired
private TaskService taskService;
}

Question:

What is wrong?

Answer:

@DataJpaTest loads the JPA slice, not normal service beans. Use a unit test for service logic or @SpringBootTest if Spring integration is needed.


62. Tiny Bug Practice 4

Problem:

A test sometimes passes and sometimes fails.

Possible causes:

depends on current time
depends on test order
depends on random data
depends on external API
shared mutable state

Fix:

make data explicit
use fixed Clock
mock external services
avoid test order dependency
reset shared state

Practice Questions and Answers

Question 1

Why do we write tests?

Answer:

We write tests to protect application behavior, catch bugs, prevent regressions, and document how the system should work.


Question 2

What is the test pyramid?

Answer:

The test pyramid means having many fast unit tests, some slice/integration tests, and fewer slow end-to-end tests.


Question 3

What is a unit test?

Answer:

A unit test tests one small piece of code, usually one class or method, in isolation.


Question 4

Does a unit test need Spring context?

Answer:

No. A true unit test usually does not start the Spring context.


Question 5

What is a slice test?

Answer:

A slice test loads only a specific part of the Spring application context, such as MVC or JPA.


Question 6

What is an integration test?

Answer:

An integration test checks multiple parts of the application working together.


Question 7

What does @SpringBootTest do?

Answer:

@SpringBootTest loads the full Spring Boot application context.


Question 8

What does @WebMvcTest test?

Answer:

@WebMvcTest tests the web layer, including controllers, request mapping, validation, JSON, and controller advice.


Question 9

What does @DataJpaTest test?

Answer:

@DataJpaTest tests JPA components such as entities, repositories, mappings, and queries.


Question 10

What does @MockBean do?

Answer:

@MockBean replaces a Spring bean in the test context with a Mockito mock.


Question 11

What is the difference between mock() and @MockBean?

Answer:

mock() creates a plain Mockito mock for unit tests. @MockBean creates/replaces a mock bean inside the Spring test context.


Question 12

What is Spring TestContext?

Answer:

Spring TestContext manages Spring application contexts for tests and supports dependency injection, test properties, profiles, transactions, and context caching.


Question 13

Why are Spring tests slower than unit tests?

Answer:

Because they may start application context, create beans, load auto-configuration, connect to databases, initialize filters, and run migrations.


Question 14

What is context caching?

Answer:

Context caching means Spring can reuse the same test application context across tests with the same configuration.


Question 15

What does @DirtiesContext do?

Answer:

@DirtiesContext tells Spring that the context was changed and should not be reused.


Question 16

Why use @ActiveProfiles("test")?

Answer:

To use test-specific configuration, such as test database URLs, fake integrations, or disabled external services.


Question 17

Why can H2 be risky for repository tests?

Answer:

Because H2 can behave differently from production databases like PostgreSQL, especially with native SQL, constraints, JSON, date/time, and locking behavior.


Question 18

What is Testcontainers useful for?

Answer:

Testcontainers is useful for running real infrastructure like PostgreSQL, Redis, or Kafka in Docker during integration tests.


Question 19

What does deterministic test mean?

Answer:

A deterministic test gives the same result every time and does not randomly pass or fail.


Question 20

How do I choose the right test type?

Answer:

Choose the smallest test that proves the behavior: unit for business logic, slice test for one Spring layer, integration test for multiple layers.

Final Memory Sentences

  • Tests protect behavior.
  • Different problems need different test types.
  • The test pyramid has many unit tests and fewer full integration/E2E tests.
  • Unit tests do not start Spring.
  • Slice tests load only one part of Spring.
  • Integration tests check multiple parts together.
  • @SpringBootTest loads the full application context.
  • @WebMvcTest tests the MVC/controller layer.
  • @DataJpaTest tests repositories and JPA mapping.
  • @MockBean replaces a Spring bean with a mock.
  • Use mock() for unit tests.
  • Use @MockBean in Spring tests.
  • Spring TestContext manages test application contexts.
  • Spring tests are slower because they start Spring infrastructure.
  • Spring caches test contexts.
  • Use @DirtiesContext rarely.
  • Use test profiles for test configuration.
  • H2 is fast but may differ from PostgreSQL.
  • Testcontainers provides production-like infrastructure.
  • Tests should be independent and deterministic.
  • Choose the smallest test that proves the behavior.