【问题标题】:JUnit FindById returns null pointer (Mockito)JUnit FindById 返回空指针 (Mockito)
【发布时间】:2020-02-11 18:26:14
【问题描述】:

我正在尝试为我的项目中的一项服务编写 JUnit 测试,但每次运行它时都会收到 NULL POINTER EXCEPTION。

谁能告诉我我的代码有什么问题???

我想要提供的服务是:

    public City findById(Long cityId) {
        logger.info("City find by ID : {}", cityId);
        return cityDao.findById(cityId)
                .orElseThrow(() -> new ResourceNotFoundException(ErrorMessageEN.NO_CITY_FOUND_IN_DB));
    }

JUnit 是:

import static org.mockito.Mockito.when;
import java.util.Optional;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
class CityServiceImplTest {
    @InjectMocks
    private CityService cityService;

    @Mock
    private CityDao cityDao;

    private City city = new City();
    private Region region = new Region();

    @Before
    public void init() {
        city.setId(1L);
        city.setPinCode("1234");
        city.setCityName("Mumbai");

        region.setId(1L);
        region.setRegionName("Test");

        city.setRegion(region);
        MockitoAnnotations.initMocks(this);
    }

    @Test
    void findById_SUCCESS() {
        when(cityDao.findById(1L)).thenReturn(Optional.of(city));
        cityService.findById(1L);
    }
}

这是它的堆栈跟踪:

java.lang.NullPointerException
    at com.recupmespoints.api.service.impl.CityServiceImplTest.findById_SUCCESS(CityServiceImplTest.java:48)
    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.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.util.ArrayList.forEach(ArrayList.java:1257)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
    at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.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)

【问题讨论】:

  • 能否提供异常堆栈转储?
  • 异常中包含的信息对于了解问题所在至关重要。是的,all 信息来自异常。只是说您有NullPointerException,您并没有为我们提供足够的工具来帮助您。
  • 我添加了堆栈跟踪看看它
  • 我只能假设您的 CityService 不仅仅依赖于 CityDao。在那种情况下,Mockito will not report any errors,你就不会在那里注入任何东西。
  • 不,它只取决于作为存储库的 CityDao

标签: java spring-boot junit mockito


【解决方案1】:

您的测试类有几个问题:

  • 小一:你不需要同时使用MockitoAnnotations.initMocks(this);@RunWith(MockitoJUnitRunner.class)。他们基本上都在做同样的事情。
  • 大一:你的测试类必须是public:public class CityServiceImplTest {...}

  • 另一个主要问题:您正在使用带有 JUnit 5 注释 org.junit.jupiter.api.Test 的 JUnit 4 运行器 org.mockito.junit.MockitoJUnitRunner。我建议通过导入 org.junit.Test 来坚持使用 JUnit 4。

您在 JUnit 4 中的测试的简化版本是:

import static org.mockito.Mockito.when;

import java.util.Optional;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class CityServiceImplTest {

  @InjectMocks
  CityService cityService;

  @Mock
  CityDao cityDao;

  private City city = new City();

  @Before
  public void init() {
    city.setId(1L);
    city.setPinCode("1234");
    city.setCityName("Mumbai");
  }

  @Test
  public void findById() {
    when(cityDao.findById(1L)).thenReturn(Optional.of(city));
    cityService.findById(1L);
  }
}

但如果你想使用 JUnit 5,你必须使用 @BeforeEach@ExtendWith(MockitoExtension.class)

import java.util.Optional;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class CityServiceImplTest {

  @InjectMocks
  CityService cityService;

  @Mock
  CityDao cityDao;

  private City city = new City();

  @BeforeEach
  public void init() {
    city.setId(1L);
    city.setPinCode("1234");
    city.setCityName("Mumbai");
  }

  @Test
  public void findById() {
    when(cityDao.findById(1L)).thenReturn(Optional.of(city));
    cityService.findById(1L);
  }
}

【讨论】:

  • 他也可以用@BeforeEach 替换@Before,以始终如一地使用JUnit 5(那么他也根本不需要@RunWith)。
  • @M.Prokhorov 你是对的,但 JUnit 5 可能需要更多的改变。
  • 不,不一定。如果他不使用任何规则,那就是他唯一需要的改变。
【解决方案2】:

尝试使用 import org.junit.Test 而不是 import org.junit.jupiter.api.Test 因为@org.junit.runner.RunWith 不是来自junit5

【讨论】:

  • 是的,你是对的,但这不是唯一的问题。请看我的回答。
  • @HakanDilek 我同意那里还有一些问题。但是从您在回复中提到的几点来看,哪一个导致空指针? IMO 它与我建议的相同。请分享您的意见。
  • org.mockito.junit.MockitoJUnitRunner@Before 在 JUnit 5 上下文中均无效,因此未初始化模拟。这就是 NPE 的原因。
【解决方案3】:

您的init() 方法使用org.junit.Before 注释进行标记,但整个测试是使用JUnit 5 运行的,JUnit 5 无法识别要作为设置过程的一部分调用的方法。意思是 MockitoAnnotations.injectMocks 也永远不会被调用。

如果您希望使用 JUnit5,则应使用 @BeforeEach 注释您的设置,因为它是 JUnit 5 的等效注释。

或者,您可以采用其他用户已经提出的建议并坚持使用 JUnit 4 API。

主要的一点是 - 不要混合 JUnit 版本,即使这样有效,也是偶然的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-24
    • 2021-06-15
    • 2016-08-19
    • 2021-06-30
    • 1970-01-01
    • 2019-04-09
    • 1970-01-01
    • 2017-06-27
    相关资源
    最近更新 更多