首页 > 解决方案 > Mockito junit 测试不起作用-@mockBean 模拟的 bean 为空

问题描述

我正在尝试 Mockito 进行模拟和单元测试。

尝试使用@MockBean. 但是 bean 在运行时为空。

正在测试的班级。

@Service
public class UserServiceImpl  {

  @Autowired
  GenericRestClient restClient;

  @Autowired
  RequestMapper requestMapper;

  @Autowired
  ResponseMapper responseMapper;

  @Override
  public List<User> findUsers(RRequest requestBody,
      String index) throws HostException {
List<User> users= 
requestMapper.mapRequest("test");
// ...doing something
return users;
}

测试类:


import static org.junit.Assert.assertNotNull;

import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.boot.test.mock.mockito.MockBean;

@RunWith(MockitoJUnitRunner.class)

public class UserServiceImplTest {

    @MockBean
    GenericRestClient restClient;

    @MockBean
    RequestMapper requestMapper;

    @MockBean
    ResponseMapper responseMapper;

    @InjectMocks
    UserServiceImpl userService;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

    }

    @Test
    public void testFindUsers() {
List<Users> users = null;
        Mockito.when(requestMapper.mapRequest("test"))
        .thenReturn(users); 
        assertNull(users);      
    }
}

错误 :

java.lang.NullPointerException
    at test.my.code.UserServiceImplTest.testFindUsers(UserServiceImplTest.java:10)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79)
    at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
    at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
    at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)


我已经调试过,NullPointerException是因为requestMapper(使用 MockBean 进行模拟null。)

这段代码有什么问题?

标签: unit-testingjunitmockito

解决方案


与@abinmichael 不同,我不建议使用 Spring Runner 来运行此测试。你的测试是单元测试,运行Spring(创建应用上下文)是一个非常昂贵的操作,更适合集成测试。

我不是 mockito 专家,但我相信,你应该稍微重构一下,UserServiceImpl以便依赖项变得可见:

@Service
public class UserServiceImpl  {


 private final GenericRestClient restClient;
 private final RequestMapper requestMapper;
 private final ResponseMapper responseMapper;

 @Autowired // in recent spring version, this annotation can be omitted 
 public UserServiceImpl(GenericRestClient restClient, RequestMapper requestMapper, ResponseMapper responseMapper) {
    this.restClient = restClient;
    this.requestMapper = requestMapper;
    this.responseMapper = responseMapper;    
 }
 ...

使用这种方法,不再需要@InjectMocks

@RunWith(MockitoJUnitRunner.class)

public class UserServiceImplTest {

@Mock
GenericRestClient restClient;

@Mock
RequestMapper requestMapper;

@Mock
ResponseMapper responseMapper;


UserServiceImpl userService;

@Before 
public void init() {
  userService = new UserServiceImpl(restClient, requestMapper, responseMapper);
}

....
}

如果您坚持使用字段注入,请阅读接受的答案以获取有关如何@InjectMocks工作的更多信息。也许您没有“私有”访问修饰符,也许您在构造函数注入和字段注入之间有一些混合,并且@InjectMocks不能同时支持两者


推荐阅读