Search code examples
javaspringspring-bootjacksonjunit5

Jackson ObjectMapper is null in JUnit 5 Controller Test


I have tried with @Autowired on the objectMapper, also tried to Mock it but no success, I just want to use the writeValueAsStringMethod so I do not have to pass a long json string to the content method below.

If I mark my class with @SpringBootTest and also @AutoconfigureMockMvc it works (the objectmapper is not null) but I believe that there must be another way so that it does not become mandatory to use this annotations.

TestClass:

@ExtendWith(MockitoExtension.class)
public class CarControllerTest {

    private MockMvc mockMvc;

    @InjectMocks
    private CarController carController;

    @Mock
    private ObjectMapper objectMapper;

    @MockBean
    private CarParts carParts;

    @BeforeEach
    public void before() {
        mockMvc = MockMvcBuilders.standaloneSetup(carController).build();
    }

    @Test
    @DisplayName("Car Controller Test")
    public void carControllerTest() {

        try {
            CarCustomRequest carCustomRequest = buildRequest();
            ResultActions resultActions = mockMvc.perform(post("/custom/endpoint")
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(objectMapper.writeValueAsString(carCustomRequest)));
            MvcResult mvcResult = resultActions.andExpect(status().isOk()).andReturn();
            assertTrue(mvcResult.getResponse().getStatus() == 200);
        } catch (Exception e) {
            fail("Error testing /custom/endpoint");
        }
    }

Solution

  • In order to @Autowire you need to load component classes that create the corresponding bean. To make tests faster you could define custom application context and load required beans only inter of using @SpringBootTest without params.

    @SpringBootTest(classes = JacksonAutoConfiguration.class)
    class ObjectMapperTest {
    
        @Autowired
        private ObjectMapper mapper;
    
        @Test
        void checkObjectMapper() {
            assertNotNull(mapper);
        }
    }
    

    I would not use @Mock in this case because it will be required to create stubs for required methods.

    As an alternative, you could simply create a new instance of the ObjectMapper in test.

    class ObjectMapperTest {
        private ObjectMapper mapper = new ObjectMapper();
    
        @Test
        void checkObjectMapper() {
            assertNotNull(mapper);
        }
    }
    

    You could also register additional modules if required

    objectMapper.registerModule(new JavaTimeModule());