首页 > 解决方案 > 空指针异常 JUnit Mockito

问题描述

我是 JUnit 和 Mockitio 的新手。当我运行下面的代码时,我得到 java.lang.NullPointerException: Cannot invoke "org.springframework.http.ResponseEntity.getStatusCodeValue()" 因为返回值 "com.learnit.testing.MyController.getUser(java.lang .Long)" 为空

@Controller
@RequestMapping("/api")
public class MyController {

    @Autowired
    private MyService service;

    @GetMapping("/")
    @ResponseBody
    public ResponseEntity<Object> getUser(Long id) throws Exception {
        return service.myResponse(id);
    }
}

@Service
public class MyService {
    
    @Autowired
    private MyRepository repository;

    public ResponseEntity<Object> myResponse(Long id) throws Exception{

        MyData data=repository.findById(id).orElse(null);
        if(data!=null)
            return new ResponseEntity<>(HttpStatus.OK);
        return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);

    }
}

测试

@ExtendWith(MockitoExtension.class)
public class MyTest {

    @InjectMocks
    private MyController controller;
    
    @Mock
    private MyRepository repo;
    
    @Mock
    private MyService service;
    
    @Test
    public void checkService() throws Exception {
        when(repo.findById((long)1)).thenReturn(null);
        assertEquals(controller.getUser((long)1).getStatusCodeValue(), 500);
        
    }
}

标签: javaspring-bootjunitmockito

解决方案


There are several issues:

  1. You did not stub the behaviour of the MyService#myResponse method. You need to mock the MyService instance as this is the direct dependency of the MyController instance. Therefore, the MyRepository don't needs to be mocked in this test case (unless you want to stub its methods for some reason, but I don't it in the current code). I would recommend you to replace the following:
        when(repo.findById((long)1)).thenReturn(null);

with stubbing behaviour of the MyService mock instance:

        when(service.myResponse(1L)).thenReturn(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));

When you do this, the MyRepository test suite mock instance can be removed, as it is not required anymore.

  1. Check your imports, based on the usage of @ExtendWith annotation I assume you are using JUnit 5 here. Make sure that you actually use other classes from org.junit.jupiter.api(for example @Test and Assertions). By default, the JUnit does not support backward compatibility with the JUnit 4. Still, I you want to keep the compatibility you should include the junit-vintage-engine artifact in your test runtime path.

P.S You need to think which class you actually want to test, that determines which instances should be mocked.


推荐阅读