intermediate~2h

Testing APIs & Dockerized Postgres

Closing out the REST & Database arc: how to actually verify your API by hand, then how to run a real database locally without installing Postgres directly on your machine.

Learning objectives

  • Beginner: Manually exercise an API's endpoints with Postman to confirm request/response shapes before writing automated tests.
  • Intermediate: Run a real Postgres instance locally via Docker instead of relying on an in-memory substitute like H2.
  • Advanced: Write a MockMvc-based test that verifies both the HTTP contract and the underlying persistence behavior together.

Before any UI exists, Postman (or a similar HTTP client) is how you actually exercise the API you just built — setting request method, headers, and JSON body directly, then inspecting the raw response instead of relying on a frontend to exist first.

Postman featureWhy it matters
CollectionsGroup and save every endpoint of your API as reusable, shareable requests, instead of retyping URLs each time.
EnvironmentsSwap a base URL/variable between local, staging, and production without editing every saved request.
Pre-request scriptsAutomatically attach a fresh auth token (Module 13) before a request fires, rather than copy-pasting one manually.

◆ The problem

Installing Postgres natively means managing a system service, dealing with OS-specific install quirks, and potential version conflicts with any other project on the same machine needing a different Postgres version.

docker run --name bookdb -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=bookdb -p 5432:5432 -d postgres:16

application.properties pointed at the containerized DB

spring.datasource.url=jdbc:postgresql://localhost:5432/bookdb spring.datasource.username=postgres spring.datasource.password=secret

Your Spring Boot application connects to this containerized Postgres exactly as if it were installed natively — JDBC doesn't know or care that the database is running inside a container. Deleting the container (docker rm bookdb) removes it cleanly with zero residue on your machine, unlike a native uninstall.

💻 Code example

docker run --name bookdb -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=bookdb -p 5432:5432 -d postgres:16
@WebMvcTest(BookController.class) class BookControllerTest { @Autowired private MockMvc mockMvc; @MockBean private BookService bookService; @Test void getBook_returns200() throws Exception { when(bookService.findById(1L)) .thenReturn(new BookResponse(1L, "Clean Code", "Robert Martin", Instant.now())); mockMvc.perform(get("/books/1")) .andExpect(status().isOk()) .andExpect(jsonPath("$.title").value("Clean Code")); } @Test void getBook_notFound_returns404() throws Exception { when(bookService.findById(999L)).thenThrow(new BookNotFoundException(999L)); mockMvc.perform(get("/books/999")) .andExpect(status().isNotFound()); } }

This directly exercises Module 10's @ControllerAdvice too — the 404 test above only passes if BookNotFoundException is genuinely mapped correctly by the global exception handler, not just because the service method threw something.

✓ Quick recap

Does your Spring Boot app need to know the database is containerized? No — JDBC connects to a host:port exactly the same way regardless of whether Postgres is native or in Docker. What does @WebMvcTest deliberately not load, and why does that matter here? The full application context — only the web layer, with the service mocked, so the test isolates controller + exception-handling behavior specifically.

💻 Code example

@WebMvcTest(BookController.class) class BookControllerTest { @Autowired private MockMvc mockMvc; @MockBean private BookService bookService; @Test void getBook_returns200() throws Exception { when(bookService.findById(1L)) .thenReturn(new BookResponse(1L, "Clean Code", "Robert Martin", Instant.now())); mockMvc.perform(get("/books/1")) .andExpect(status().isOk()) .andExpect(jsonPath("$.title").value("Clean Code")); } @Test void getBook_notFound_returns404() throws Exception { when(bookService.findById(999L)).thenThrow(new BookNotFoundException(999L)); mockMvc.perform(get("/books/999")) .andExpect(status().isNotFound()); } }

Want a visual for this concept?

Generate a diagram tailored to “Testing APIs & Dockerized Postgres” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.

Sign in to generate a visual →

Practice quiz

Next Step

Continue to Spring Security Fundamentals← Back to all Spring Boot chapters