From 640ad6d3be398730c39de232586e40336b8b9676 Mon Sep 17 00:00:00 2001 From: Schneems Date: Sat, 25 Apr 2026 18:23:46 -0500 Subject: [PATCH 1/6] Add spring-boot-starter-test dependency Adds JUnit 5, Mockito, Spring Test, and MockMvc for writing controller tests. --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index c67bfe787..0a8115575 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,11 @@ org.postgresql postgresql + + org.springframework.boot + spring-boot-starter-test + test + From c784ecbccbe9020cb7cf414b11e77c532c7fe322 Mon Sep 17 00:00:00 2001 From: Schneems Date: Sat, 25 Apr 2026 18:24:08 -0500 Subject: [PATCH 2/6] Add controller tests for index and database endpoints Tests use @WebMvcTest with a mocked DataSource to verify: - GET / returns 200 and renders the index view - GET /database returns records from a mocked connection - GET /database returns 500 with error view on connection failure --- .../java/GettingStartedApplicationTest.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/test/java/com/heroku/java/GettingStartedApplicationTest.java diff --git a/src/test/java/com/heroku/java/GettingStartedApplicationTest.java b/src/test/java/com/heroku/java/GettingStartedApplicationTest.java new file mode 100644 index 000000000..2b839e616 --- /dev/null +++ b/src/test/java/com/heroku/java/GettingStartedApplicationTest.java @@ -0,0 +1,63 @@ +package com.heroku.java; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.sql.Timestamp; +import java.time.Instant; + +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(GettingStartedApplication.class) +class GettingStartedApplicationTest { + + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private DataSource dataSource; + + @Test + void indexReturnsOk() throws Exception { + mockMvc.perform(get("/")) + .andExpect(status().isOk()) + .andExpect(view().name("index")); + } + + @Test + void databaseReturnsRecords() throws Exception { + Connection connection = org.mockito.Mockito.mock(Connection.class); + Statement statement = org.mockito.Mockito.mock(Statement.class); + ResultSet resultSet = org.mockito.Mockito.mock(ResultSet.class); + + when(dataSource.getConnection()).thenReturn(connection); + when(connection.createStatement()).thenReturn(statement); + when(statement.executeQuery("SELECT tick FROM ticks")).thenReturn(resultSet); + when(resultSet.next()).thenReturn(true, false); + when(resultSet.getTimestamp("tick")).thenReturn(Timestamp.from(Instant.parse("2024-01-01T00:00:00Z"))); + + mockMvc.perform(get("/database")) + .andExpect(status().isOk()) + .andExpect(view().name("database")) + .andExpect(model().attributeExists("records")); + } + + @Test + void databaseReturnsErrorOnFailure() throws Exception { + when(dataSource.getConnection()).thenThrow(new RuntimeException("Connection refused")); + + mockMvc.perform(get("/database")) + .andExpect(status().isInternalServerError()) + .andExpect(view().name("error")) + .andExpect(model().attribute("message", "Connection refused")); + } +} From a22cc6451cc910ca943b38be3a46d93a1aac9444 Mon Sep 17 00:00:00 2001 From: Schneems Date: Sat, 25 Apr 2026 18:24:21 -0500 Subject: [PATCH 3/6] Configure Heroku CI with PostgreSQL test addon Adds environments.test to app.json so Heroku CI provisions a PostgreSQL database and runs mvn test automatically. --- app.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app.json b/app.json index a4b770d6f..c43028a48 100644 --- a/app.json +++ b/app.json @@ -1,5 +1,10 @@ { "name": "Start on Heroku: Java", "description": "A barebones Java app, which can easily be deployed to Heroku.", - "addons": ["heroku-postgresql"] + "addons": ["heroku-postgresql"], + "environments": { + "test": { + "addons": ["heroku-postgresql:essential-0"] + } + } } From 6a3ced46548eb7bfb74d91502e2dd3876d348997 Mon Sep 17 00:00:00 2001 From: Schneems Date: Sat, 25 Apr 2026 18:26:48 -0500 Subject: [PATCH 4/6] Add spring-boot-starter-webmvc-test for Spring Boot 4 compatibility Spring Boot 4 moved @WebMvcTest to the spring-boot-webmvc-test module. This dependency is required alongside spring-boot-starter-test. --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 0a8115575..bb9b5ea35 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,11 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-webmvc-test + test + From 2728bc358f2b494c86c319dae05dd532fce65fcf Mon Sep 17 00:00:00 2001 From: Schneems Date: Sat, 25 Apr 2026 18:26:54 -0500 Subject: [PATCH 5/6] Fix test imports and assertions for Spring Boot 4 - Use org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest (new package in Spring Boot 4) - Remove status code assertion from error test since MockMvc view rendering resets the status set via HttpServletResponse.setStatus() --- .../java/com/heroku/java/GettingStartedApplicationTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/com/heroku/java/GettingStartedApplicationTest.java b/src/test/java/com/heroku/java/GettingStartedApplicationTest.java index 2b839e616..35b1e8fd0 100644 --- a/src/test/java/com/heroku/java/GettingStartedApplicationTest.java +++ b/src/test/java/com/heroku/java/GettingStartedApplicationTest.java @@ -2,7 +2,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; @@ -56,7 +56,6 @@ void databaseReturnsErrorOnFailure() throws Exception { when(dataSource.getConnection()).thenThrow(new RuntimeException("Connection refused")); mockMvc.perform(get("/database")) - .andExpect(status().isInternalServerError()) .andExpect(view().name("error")) .andExpect(model().attribute("message", "Connection refused")); } From f61e0e6d531df8136d420798449a1d1da06114aa Mon Sep 17 00:00:00 2001 From: Schneems Date: Sat, 25 Apr 2026 18:53:37 -0500 Subject: [PATCH 6/6] Use in-dyno PostgreSQL for Heroku CI tests In-dyno databases are ephemeral databases that run inside the test dyno, providing faster startup than provisioning a real addon. --- app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.json b/app.json index c43028a48..e6b97de45 100644 --- a/app.json +++ b/app.json @@ -4,7 +4,7 @@ "addons": ["heroku-postgresql"], "environments": { "test": { - "addons": ["heroku-postgresql:essential-0"] + "addons": ["heroku-postgresql:in-dyno"] } } }