简体   繁体   中英

Spring MVC Test failing

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:

  1. 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.

  2. Use webAppContext setup:

     @Autowired private WebApplicationContext webApplicationContext; @BeforeMethod public void init() { mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); } 

You need to configure your test to inject your autowired properties. See the following code block:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class AccountControllerITest {

    // ... your test code

    @Configuration
    public static class YourConfiguration {

        @Bean
        AccountService accountService() {
            // init and return your AccountService
        }
    }
}

You can init your AccountService with Mockito .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM