Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Percisely configure spring junit 5 test config

Struggling for quite some with writing unit tests with spring-boot and junit5. I've read lots of articles and some of the junit5 documentation but didn't find anything that would help (or I'm just blind).

test:

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = ScoreTestConfiguration.class)
@AutoConfigureMockMvc
public class ScoreControllerTest {

private static final String SCORE_ENDPOINT = "/scoring";

private static final ObjectMapper MAPPER = new ObjectMapper();

@Autowired
private MockMvc mockMvc;
@MockBean
private ScoreService mockScoreService;

@BeforeEach
public void setUp() {
    ScoreResponseDto response = getScoreResponseDto();
    when(mockScoreService.getScore(any(),any(),any(),any(),any(),any())).thenReturn(response);
}

@NotNull
private ScoreResponseDto getScoreResponseDto() {
    ScoreResponseDto response = new ScoreResponseDto();
    response.setCid("qwe13423qw");
    response.setData(new ScoreResponseDto.ScoringData(0.78f));
    return response;
}


@Test
public void sendValidRequest_getResponse_andOkStatus() throws Exception {
    String request = SCORE_ENDPOINT +
            "/380715346789" + //msisdn
            "?score_formula=1234" +
            "&clientId=5678" +
            "&cid=543" +
            "&stateType=" + StateType.ACTIVE.name() +
            "&subscriberType=" + SubscriberType.POSTPAID.getValue();
    String jsonResponse = MAPPER.writeValueAsString(getScoreResponseDto());
    System.out.println("jsonResponse: " + jsonResponse);
    mockMvc.perform(get(request))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(content().string(jsonResponse));
}

}

configuration (it's an experiment to get only certain only certain classes but I failed):

@Configuration
@ComponentScan(basePackages = "com.some.path.to.rest")
class ScoreTestConfiguration {

}

While test execution , I assume, that global context is been initiated despite that I specified to load only part of it in @Configuration class.

My question how can I control and setup precise configuration of test context for spring-boot and junit5 test.

Actually if somebody will give some references about best practices hot to organize local testing framework I'll be really grateful. Thank you in advance!

like image 351
Miklosh Avatar asked Mar 11 '26 12:03

Miklosh


1 Answers

Without seeing more of your code, it's hard to tell why your test configuration does not meet your needs. I've created a sample project with a few different examples similar to your case and some other - you can find it here on GitHub. Below is the list of examples you can find there with a short description.


@SpringBootTest(classes = TestedController.class)
@AutoConfigureMockMvc
public class TestWithoutConfiguration {

    @Test
    void fails() {

    }

}

This test fails, since no configuration (apart from the controller bean) is provided - no beans can be found and injected.


@SpringBootTest(classes = {TestedController.class, TestConfiguration.class})
@AutoConfigureMockMvc
public class TestWithTestButWithoutMockBeanConfiguration {

    @Test
    void fails() {

    }

}

Here we use a test configuration that provides a service bean for our controller, but we still lack a bean used by that service - MockedUtilInterface (see below).


@SpringBootTest(classes = {TestedController.class, TestConfiguration.class})
@AutoConfigureMockMvc
public class TestWithTestConfiguration {

    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private MockedUtilInterface mockedUtil;

    @Test
    void test() throws Exception {
        when(mockedUtil.value())
                .thenReturn(100);

        mockMvc.perform(get("/test"))
               .andExpect(content().string("100 - rest service from component scan value"));
    }

}

This test passes - TestConfiguration provides the service bean and we're also creating a MockedUtilInterface bean as a mock. The mock is injected into the service to which the test configuration points and the service is injected into the actual controller.


@SpringBootTest
@AutoConfigureMockMvc
public class TestWithActualConfiguration {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void test() throws Exception {
        mockMvc.perform(get("/test"))
               .andExpect(content().string("0 - not a test value"));
    }

}

This test also passes and it uses all the actual configuration, no test configuration is loaded, so all the beans are the beans from our actual application (as if it was run in a container).


@SpringBootTest
@AutoConfigureMockMvc
public class TestWithInnerTestConfiguration {

    @Configuration
    @Import(TestedApplication.class)
    static class InnerConfiguration {

        @Bean
        TestedServiceInterface service(MockedUtilInterface mockedUtil) {
            return () -> mockedUtil.value() + " - inner value";
        }

    }

    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private MockedUtilInterface mockedUtil;

    @Test
    void test() throws Exception {
        when(mockedUtil.value())
                .thenReturn(12345);

        mockMvc.perform(get("/test"))
               .andExpect(content().string("12345 - inner value"));
    }

}

And here's an example of an inner class configuration that overrides some beans, uses some actual beans and can also make use of provided @MockBeans.


Here you can find quite a few ways to configure the beans for a test.

like image 196
Jonasz Avatar answered Mar 14 '26 02:03

Jonasz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!