Step-by-step instructions

These instructions follow on from what was achieved in the previous lesson.

Add integration test to app subproject

  1. in app’s build script, add a new testImplementation dependency on spring-boot-starter-test

    testImplementation("org.springframework.boot:spring-boot-starter-test:2.6.4")
    
  2. configure test task to use JUnit 5 (also known as JUnit Jupiter)

    testing {
        suites {
            named("test", JvmTestSuite::class) {
                useJUnitJupiter()
            }
        }
    }
    
  3. under src create directories test/java/com/tomgregory/maxirail

  4. add a MaxiRailIT.java class

    package com.tomgregory.maxirail;
    
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.context.junit.jupiter.SpringExtension;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
    
    import static org.hamcrest.Matchers.hasSize;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
    
    @ExtendWith(SpringExtension.class)
    @SpringBootTest
    @AutoConfigureMockMvc
    public class MaxiRailIT {
        @Autowired
        private MockMvc mockMvc;
    
        @Test
        public void getsAllTrainTimes() throws Exception {
            mockMvc.perform(MockMvcRequestBuilders.get("/")
                            .accept(MediaType.APPLICATION_JSON))
                    .andExpect(status().isOk())
                    .andExpect(jsonPath("$", hasSize(4)))
                    .andReturn();
        }
    }
    
  5. run ./gradlew test and see that the test passes

  6. view test report in build directory of app subproject

Add unit test to service subproject

  1. in service’s build script configure test task to use JUnit 5 (also known as JUnit Jupiter)

    testing {
        suites {
            named("test", JvmTestSuite::class) {
                useJUnitJupiter()
            }
        }
    }
    
  2. under src create directories test/java/com/tomgregory/maxirail/service

  3. add a TrainTimeServiceTest.java class

    package com.tomgregory.maxirail.service;
    
    import org.junit.jupiter.api.Test;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    
    public class TrainTimeServiceTest {
        @Test
        public void swapsDestinationStationToUppercase() {
            TrainTimeService trainTimeService = new TrainTimeService();
            assertEquals("BRIGHTON", trainTimeService.getTrainTimes().get(0).destinationStation());
            assertEquals("BRIGHTON", trainTimeService.getTrainTimes().get(1).destinationStation());
            assertEquals("LONDON", trainTimeService.getTrainTimes().get(2).destinationStation());
            assertEquals("LONDON", trainTimeService.getTrainTimes().get(3).destinationStation());
        }
    }
    
  4. run the test with ./gradlew test and see it fail

  5. make the test pass by updating the destination station names in TrainTimeService.java

    package com.tomgregory.maxirail.service;
    
    import com.tomgregory.maxirail.model.TrainTime;
    import org.springframework.stereotype.Service;
    
    import java.time.LocalTime;
    import java.util.Arrays;
    import java.util.List;
    
    @Service
    public class TrainTimeService {
        public List<TrainTime> getTrainTimes() {
            return Arrays.asList(
                    new TrainTime("London", "BRIGHTON", LocalTime.of(9, 30), LocalTime.of(10, 30)),
                    new TrainTime("London", "BRIGHTON", LocalTime.of(15, 0), LocalTime.of(16, 0)),
                    new TrainTime("Brighton", "LONDON", LocalTime.of(11, 0), LocalTime.of(12, 0)),
                    new TrainTime("Brighton", "LONDON", LocalTime.of(16, 30), LocalTime.of(17, 30))
            );
        }
    }
    
  6. run the test again with ./gradlew test --console=verbose. This time it passes.

  7. note that it also runs tests against the app subproject. You can avoid that by running the test task specifically on the service subproject, using the fully qualified task name.

  8. run ./gradlew service:test --console=verbose

Awesome! You now know how and when to execute tasks against specific subprojects.

GitHub repository

The gradle-multi-project-masterclass repository contains the final code solution for lessons 2-5.