codingstairs
NotesEDULifeContact
⌕Search⌘K
koen

Navigation

  • Intro
  • Blog
  • Life

Get in touch

Send without signing in. Add your email if you'd like a reply.

  • Leave a message anonymously →
  • ✉ warragon112@gmail.com
  • KakaoTalk Open Chat ↗

© 2026 codingstairs

  • Notes
  • EDU
  • Search
  • Life
  • Contact
  • Legal
  • RSS
  • GitHub
EDU›Backend with Spring Boot 4›Step 6

Step 6

Step 6 — Testing strategy

0 views

Step 6 — Testing strategy

Tests aren't for later — they're for now. Write them as you code and regression goes nearly to zero.

Three layers

Layer Tools What
Unit JUnit 5 + Mockito one method of one class
Integration @SpringBootTest + Testcontainers several beans + real DB
E2E RestAssured / Playwright HTTP request → response

For new code, write unit + integration. E2E covers the critical paths.

Integration tests with Testcontainers

@SpringBootTest
@Testcontainers
class PostControllerTest {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17");

    @DynamicPropertySource
    static void config(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }

    @Autowired MockMvc mockMvc;

    @Test
    void create_post_returns_201() throws Exception {
        mockMvc.perform(post("/api/posts")
                .contentType("application/json")
                .content("""
                    {"title":"Hi","body":"Hello"}
                    """))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.id").exists());
    }
}

Docker auto-starts a real PostgreSQL. Better than mocks at catching real bugs.

Unit tests with Mockito

@ExtendWith(MockitoExtension.class)
class PostServiceTest {
    @Mock PostRepository repository;
    @InjectMocks PostService service;

    @Test
    void missing_id_throws_NotFoundException() {
        when(repository.findById(999L)).thenReturn(Optional.empty());

        assertThatThrownBy(() -> service.findById(999L))
            .isInstanceOf(NotFoundException.class);
    }
}

Try it

Add an integration test for DELETE /api/posts/{id}: (1) create a post, (2) delete it, (3) expect 204, (4) GET expects 404.

Next

Step 7 deploys this with Docker + Caddy.

← Step 5

Step 5 — Auth with JWT

Step 7 →

Step 7 — Deploy