简体   繁体   中英

Spring MVC Testing with Mock

I got this unit test code to test my spring mvc view, its look like failing to initialize the service.

@AutoConfigureMockMvc
@ContextConfiguration(classes = { TestAppContext.class })
@WebMvcTest
@Transactional
class BillEntryControllerTest {

    
    @Autowired
    private BillEntryService billEntryService;

    @Autowired
    private MockMvc mockMvc;

    @BeforeEach
    public void setup() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(new BillEntryController())
            .build();
    }

    @Test
    public void checkUpdateBill() throws Exception {
        billEntryService = Mockito.mock(BillEntryServiceImpl.class);

        doNothing().when(billEntryService).addOrUpdateBill(any(BillEntry.class));

        this.mockMvc
                .perform(MockMvcRequestBuilders.post("/bill-entry/saveBillEntry").accept(MediaType.TEXT_HTML)
                        .param("amount", "10.0")
                        .param("owner", "User")
                        .param("property", "Prop")
                        .param("receiptNumber", "ABC")
                        .param("accountName", "AC")
                        .param("billerName", "BN")
                        .param("datePaid", "20/10/2022")
                        .param("dateDue", "20/10/2022"))
                .andExpect(model().errorCount(0)).andExpect(status().isOk());
    }

}

And getting following error

Caused by: java.lang.NullPointerException: Cannot invoke "org.de.service.BillEntryService.addOrUpdateBill(org.de.model.BillEntry)" because "this.billEntryService" is null at org.de.controller.BillEntryController.saveBillEntry(BillEntryController.java:157)

@PostMapping("/saveBillEntry")
public String saveBillEntry(Model model, @Valid @ModelAttribute("billEntry") BillEntryFormDto dto,
        BindingResult theBindingResult) {
    BillEntry billEntry = new BillEntry();
    if (dto.getBillId()!=null && !dto.getBillId().isEmpty()) {
        logger.debug("biller id " + dto.getBillId());
        billEntry = billEntryService.getBillEntryById(Integer.parseInt(dto.getBillId()));
    }       
    if (theBindingResult.hasErrors()) {
        logger.error("has errors ");
        getDefault(model);
        return "bill-entry-form";
    }               
    
    //updating the form attributes      
    billEntry.setAccountName(dto.getAccountName());
    billEntry.setAmount(Double.parseDouble(dto.getAmount().replaceAll("[^\\d.]", "")));
    billEntry.setBillerName(dto.getBillerName());
    billEntry.setDateDue(FormatHelper.getDateFromString(dto.getDateDue()));
    billEntry.setDatePaid(FormatHelper.getDateFromString(dto.getDatePaid()));
    billEntry.setProperty(dto.getProperty());
    billEntry.setReceiptNumber(dto.getReceiptNumber());
    billEntry.setOwner(dto.getOwner());
    
    logger.info("attempt to save/update bill entires " + billEntry.getBillId());
    logger.debug("entry  " + billEntry);
//failing at here (line 157)

    billEntryService.addOrUpdateBill(billEntry);
    return "redirect:"+ dto.getRedirect();
}

I try to mock the BillEntryService but that didn't help me ether. Any tips on how to fix it or what I'm doing wrong?

This is because your mocked billEntryService is not injected into the controller under test. As a result, that field is not initialized ( null ) in the controller during the test.

To fix that, the billEntryService must be annotated with @MockBean instead of @Autowired in the test. That will inject the mocked version of BillingEntryService into the controller. And you shouldn't initialize that mocked billEntryService using Mockito.mock(...) afterwards. The mockMvc shouldn't be initialized either, because you are using @WebMvcTest that already injects a proper mockMvc and you are autowiring it. So, the @BeforeEach method is also to be removed.

Given the above, the relevant part of the test will look like this:

@ContextConfiguration(classes = { TestAppContext.class })
@WebMvcTest
@Transactional // doesn't seem necessary here but I haven't touched this
class BillEntryControllerTest {

  @MockBean
  private BillEntryService billEntryService;

  @Autowired
  private MockMvc mockMvc;

  @Test
  public void checkUpdateBill() throws Exception {
    doNothing().when(billEntryService).addOrUpdateBill(any(BillEntry.class));
    mockMvc.perform...
  }
        

Also, you can find this answer quite helpful.

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