【问题标题】:NPE while running test in Spring application (JUnit 5, Mockito 3, Spring JPA repositories)在 Spring 应用程序中运行测试时的 NPE(JUnit 5、Mockito 3、Spring JPA 存储库)
【发布时间】:2021-12-18 01:12:01
【问题描述】:

我正在使用 Mockito 3.1.0 和 Junit 5.5.2 运行一个基本的 Spring 应用程序。我有一个包含两个 Spring Data JPA 存储库的服务调用。这些被传递到 DI 的构造函数中(以及另外两个无关紧要的 - 我将它们包括在内,以防它们也可能导致错误。)当应用程序运行时,我发现服务没有问题。

当我运行测试时,我得到了myService 的 NPE。单步执行堆栈跟踪,并没有真正向我展示与错误相关的任何内容。我也尝试过(在这篇文章之后:https://www.baeldung.com/mockito-junit-5-extension)更新我的测试类,如下所示:

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class) // This dependency doesn't seem to exist
public class MyServiceTest {
    // ...

    @BeforeEach 
    // not the JUnit4 @Before annotation.
    // Interestingly, this gives me NPEs for the repositories, not the service.
    public void setup(){
        // ...
    }
}

无济于事。我怀疑正在发生的事情是我的设置没有正确连接——无论是作为依赖项还是 DI 的语法。

我该如何调试呢?我错过了什么?提前致谢!

服务:

import org.springframework.stereotype.Service;

@Service
public class MyService {
    private final Repository1 repository1;
    private final Repository2 repository2;
    private final Repository3 repository3;
    private final Repository4 repository4;

  public MyService(Repository1 repository1,
      Repository2 repository2,
      Repository3 repository3,
      Repository4 repository4) {
    this.repository1 = repository1;
    this.repository2 = repository2;
    this.repository3 = repository3;
    this.repository4 = repository4;
  }

    public Boolean computeValue(String someInput) {
        // does computations with repository1, repository2.
    }
}

测试:

import static org.mockito.Mockito.when;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {

    @Mock
    private Repository1 repository1;

    @Mock
    private Repository2 repository2;

    @Mock
    private Repository3 repository3;

    @Mock
    private Repository4 repository4;

    @InjectMocks
    private MyService myService;

    @Before
    public void setup {
        when(repository1.findAll()).thenReturn(new ArrayList<>());
        when(repository1.findAllByInput(anyString())).thenReturn(new ArrayList<>());
        // Yes; I'm aware that this could also be a call to
        // MockitoAnnotations.initMocks(this). I've tried it:
        // it doesn't work. Also, I've intentionally not taken this
        // approach due to reasons:
        //   - https://stackoverflow.com/questions/10806345/runwithmockitojunitrunner-class-vs-mockitoannotations-initmocksthis
    }

    @Test
  void callMyService() {
        assertTrue(myService.computeValue("123"));
    }
}

示例存储库:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

// This is just an example, but this pattern is repeated against all
// repositories in the project.
@Repository
public interface Repository1 extends JpaRepository<Repository1, String> {
}

编辑:

  • 我忘了提到我在这个项目中有其他文件正在使用完全这些没有失败的注释(@RunWith(MockitoJUnitRunner.class)@Mock@InjectMocks@Before)。
  • 我使用相关导入更新了文件,并添加了RepositoryN 的示例。
  • 我更新了MyService 类以更好地反映参数。

【问题讨论】:

  • 这里出了点问题。您的代码应该可以工作。请添加完整的MyServiceMyServiceTest 代码好吗?谢谢
  • 请向我们展示导入(最好分别用于 jUnit 4 和 jUnit 5 版本)。
  • 感谢 João 和 Lesiak 的反馈。我已经添加了相关的导入并验证了上面的示例。如果您有任何问题,请 LMK。
  • 能否请附上完整的MyService 代码?构造函数看起来很奇怪。
  • 所以你用 mockito 运行测试,没有使用 Spring 来运行测试,你想知道为什么 Spring 不注入依赖项?您的测试是针对 Mockito 的,但您使用 Junit4 运行 junit5 测试,这是行不通的。抛弃 @RunWith 并使用 JUnit5 中的 @ExtendsWith

标签: java spring spring-boot junit mockito


【解决方案1】:

对于将来遇到此问题的任何其他人,我们能够通过更改其中一个导入来解决此问题:

import org.junit.jupiter.api.Test;

import org.junit.Test;

编辑:

  • 这与 JUnit 的不同版本有关。对于here 的原因,有一个很好的长篇解释。

【讨论】:

    【解决方案2】:

    似乎您的对象myService 没有被实例化。我建议不要使用 @InjectMocks 并直接创建您的对象,因为您的存储库已经实例化。 MyService myService = new MyService(..., ..., ...)

    【讨论】:

    • 感谢 Harry – 当我这样做时,有趣的是,myService 实例现在包含一堆 null 存储库。这可能表明 DI 组件 @InjectMocks 或直接构造函数 DI 不是根本原因。
    • 当您模拟您的存储库时,它们不应为空。也许你是Mockito 初始化问题。在JUnit 5 中,您使用@ExtendWith(MockitoExtension.class)。你能显示你的pom.xml 文件吗?
    【解决方案3】:

    我想你必须用@ExtendWith(SpringExtension.class)而不是MockitoExtension.class来注释你的测试类

    更多信息在这里Junit 5 with Spring Boot: When to use @ExtendWith Spring or Mockito?

    【讨论】:

    • 谢谢卢卡。我添加了一个编辑以表明我在这个项目中有其他文件正在使用 @RunWith(MockitoJUnitRunner.class) 注释并传递。我会尽快发布其余的导入。
    • 刚刚注意到,在您的存储库声明中,您的第一个通用值 Repository1。是错字吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2018-06-26
    • 2015-06-23
    • 2017-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多