using @InjectMocks outside @Before

问题: I'm creating the base for my unit testing project( Spring boot rest controller) and I'm having a problem passing @InjectMocks value because it's only evaluated in @Before a...

问题:

I'm creating the base for my unit testing project( Spring boot rest controller) and I'm having a problem passing @InjectMocks value because it's only evaluated in @Before and therefore a nullpointer is thrown when i try to access it outside

Some tips to get around the problem please?
Thank you very much

Ps : Any other advices on best practices or something i did wrong for unit testing regarding my current base class test will be appreciated as well

Class to test (rest controller)

@RestController
@RequestMapping("/management")
@Api(description = "Users count connections", produces = "application/json", tags = {"ConnectionManagement API"})
public class ConnectionManagementControllerImpl implements ConnectionManagementController {

    @Autowired
    private ConnectionManagementBusinessService connectionManagementBusinessService;

    @Override
    @PostMapping(value = "/countConnectionsByInterval" , consumes = MediaType.TEXT_PLAIN_VALUE , produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "count all users connections by interval")
    public ResponseEntity<List<ConnectionsCountDto>> countConnectionsByInterval(@RequestBody String format) {
        List<ConnectionsCountDto> connectionManagement = connectionManagementBusinessService.countConnectionsByInterval(format);
        return  new ResponseEntity<List<ConnectionsCountDto>>(connectionManagement, HttpStatus.OK);
    }

Abstract base test

public abstract class AbstractBaseTest<C> {

     public MockMvc mockMvc;

     private Class<C> clazz;

     private Object inject;

     protected abstract String getURL();

     protected final void setTestClass(final Class<C> classToSet, final Object injectToSet) {
         clazz = Preconditions.checkNotNull(classToSet);
         inject = Preconditions.checkNotNull(injectToSet);
     }

    @Before
    public void init() throws Exception {
        MockitoAnnotations.initMocks(clazz);
        mockMvc = MockMvcBuilders.standaloneSetup(inject).build();
    }

    protected MockHttpServletResponse getResponse(MediaType produces) throws Exception {
        MockHttpServletResponse response = mockMvc.perform(
                get(getURL()).
                accept(produces)).
                andReturn().
                getResponse();
        return response;
    }

    protected MockHttpServletResponse postResponse(String content , MediaType consumes , MediaType produces) throws Exception {
        MockHttpServletResponse response = mockMvc.perform(
                post(getURL()).
                content(content).
                contentType(consumes).
                accept(produces)).
                andReturn().
                getResponse();
        return response;
    }
}

Test class

@RunWith(MockitoJUnitRunner.class)
public class ConnectionManagementControllerImplTest extends AbstractBaseTest<ConnectionManagementControllerImpl>{

    @Mock
    private ConnectionManagementBusinessService connectionManagementBusinessServiceMocked;

    @InjectMocks
    private ConnectionManagementControllerImpl connectionManagementControllerMocked;

    public ConnectionManagementControllerImplTest() {
        super();            
        setTestClass(ConnectionManagementControllerImpl.class , connectionManagementControllerMocked); // null pointer there
    }

    @Test
    public void countConnectionsByInterval() throws Exception {

        // given
        given(connectionManagementBusinessServiceMocked.countConnectionsByInterval(Mockito.anyString()))
                .willReturn(new ArrayList<ConnectionsCountDto>());

        // when
        MockHttpServletResponse response = postResponse("day" , MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON_UTF8);

        // then
        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());    
    }

    @Override
    protected String getURL() {
        return "/management/countConnectionsByInterval";
    }

回答1:

This works as intended. However, you can setup mocks manually and inject them inside ConnectionManagementControllerImplTest constructor (before calling setTestClass(...)):

public ConnectionManagementControllerImplTest() {
    super();

    connectionManagementBusinessServiceMocked = Mockito.mock(ConnectionManagementBusinessService.class);

    connectionManagementControllerMocked = new ConnectionManagementControllerImpl();
    connectionManagementControllerMocked.setConnectionManagementBusinessService(connectionManagementBusinessServiceMocked);

    setTestClass(ConnectionManagementControllerImpl.class, connectionManagementControllerMocked);
}

Do not forget to remove @Mock and @InjectMocks annotations. Btw you can even remove @RunWith(MockitoJUnitRunner.class) in that case.

  • 发表于 2019-03-07 01:45
  • 阅读 ( 251 )
  • 分类:sof

条评论

请先 登录 后评论
不写代码的码农
小编

篇文章

作家榜 »

  1. 小编 文章
返回顶部
部分文章转自于网络,若有侵权请联系我们删除