I am trying to run a Spring MVC Test but keep getting this exception.
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
The exception is occuring because the autowired dependency,
@Autowired
private AccountService accountService;
is not getting injected in the test (works fine outside of the test).
Can anyone help me with this. Here is my code:
//AccountControllerITest Class
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MockServletContext.class)
@WebAppConfiguration
public class AccountControllerITest {
private MockMvc mvc;
ObjectMapper om;
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
}
@Test
public void getAccounts() throws Exception {
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/accounts"))
.andExpect(status().isOk())
.andReturn();
}
}
}
//AccountController
@RestController
@RequestMapping("/api/accounts")
public class AccountController {
@Autowired
private AccountService accountService;
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Set<AccountInfo>> getAccounts(@RequestParam(value = "firstName", required = false) String firstName,
@RequestParam(value = "surName", required = false) String surName) {
Set<AccountInfo> accounts = accountService.getAccounts(firstName, surName);
return new ResponseEntity<>(accounts, HttpStatus.OK);
}
}
Thanks for the help!
Because you are using standalone setup: mvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
. If you create controller via new AccountController()
, Spring doesn't have a chance to inject accountService
as it doesn't control instances creation and wiring.
You have two options:
Switch your test to unit test and do not use SpringJUnit4ClassRunner
nor MockServletContext
at
all. You can use @InjectMocks
to inject private accountService
:
public class AccountControllerITest {
private MockMvc mvc;
ObjectMapper om;
@Mock
private AccountController accountController = new AccountController();
@InjectMocks
private AccountService accountService = new Mockito.mock(AccountService.class);
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(accountController).build();
}
There is also enhancement you can apply to your controller. Replace field injection with constructor injection and you can pass accountService
to controller via constructor in test. This way you don't need to use @InjectMocks
at all.
Use webAppContext setup:
@Autowired
private WebApplicationContext webApplicationContext;
@BeforeMethod
public void init() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}