当前位置: 首页 > 知识库问答 >
问题:

为什么@mockbean不模拟我的目标存储库类(返回null)?

司空劲
2023-03-14

这是我要测试的类

@Component
public class PermissionCheck {

    @Autowired
    private MyEntityRepository myEntityRepository;

    public boolean hasPermission(int myEntityID) {
        MyEntity myEntity = myEntityRepository.findById(myEntityId);
        return myEntity != null;
    }
}

这是测试类

@RunWith(SpringRunner.class)
public class PermissionCheckTests {

    @MockBean
    private MyEntityRepository myEntityRepository;

    private PermissionCheck permissionCheck;

    @Before
    public void before() {
        this.permissionCheck = new PermissionCheck();
    }

    @Test
    public void shouldHasPermission() {
        MyEntity myEntity = new MyEntity();

        when(this.myEntityRepository.findById(any())).thenReturn(myEntity);
        assertTrue(this.permissionCheck.hasPermission(0));
    }
}

当我做这个测试的时候

java.lang.NullPointerException
    at PermissionCheck.hasPermission(PermissionCheck.java:line1)
    at PermissionCheckTests.shouldHasPermission(PermissionCheckTests.java:line2)
        MyEntity myEntity = myEntityRepository.findById(myEntityId);
        assertTrue(this.permissionCheck.hasPermission(0));
    @Autowired
    private MyEntityRepository myEntityRepository;

我创建这些类时参考了其他已有的代码,来自不同的地方,并且没有真正理解如何进行注释(部分原因是时间不够),所以如果有人能告诉我,不仅是如何修复,而且还有为什么我错了,我会非常感激的!

编辑:

我做了@Nikolas Charalambidis建议的更改(谢谢!),所以我的PermissionCheck类现在看起来与

@RunWith(SpringRunner.class)
public class PermissionCheckTests {

    @Autowired                                     // you need to autowire
    private PermissionCheck permissionCheck;       // and it uses @MockBean dependency

    @MockBean                                      // if no such @MockBean exists
    private MyEntityRepository myEntityRepository; // the real implementation is used

    @Test
    public void shouldHasPermission() {
        MyEntity myEntity = new MyEntity();

        when(this.myEntityRepository.findById(any())).thenReturn(myEntity);
        assertTrue(this.permissionCheck.hasPermission(0));
    }
}
org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'PermissionCheckTests': 
Unsatisfied dependency expressed through field 'permissionCheck'; 
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type 'PermissionCheck' available: 
expected at least 1 bean which qualifies as autowire candidate. 
Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=true), 
@org.springframework.beans.factory.annotation.Qualifier(value="")}

通过稍加搜索,从这个SO答案中,我觉得我不应该@autowiredpermissioncheck,因为它是一个类,而不是一个接口。

这是否意味着我必须创建一个接口,@autowired它,并让permissioncheck实现它?这对我来说似乎是多余的,因为我不明白为什么我需要这样一个接口。有没有一种方法使它工作而不创建一个新的接口,我将完全用于这个目的?

共有1个答案

郭鸿信
2023-03-14

PermissionCheck的实例未正确注入。测试以与生产代码相同的方式使用Spring容器。下面的行不会注入MyEntityRepository

this.permissionCheck = new PermissionCheck();

Spring:当包含一个bean部分地回答了您的问题时,就会发生NullPointerException。您需要@autowire这个东西。

Spring测试上下文也没有什么不同。只要@mockbeanMyEntityRepository作为模拟bean存在,PermissionCheck将以标准方式自动连接,使用模拟类优先于测试范围中的现有bean。

@RunWith(SpringRunner.class)
public class PermissionCheckTests {

    @Autowired                                     // you need to autowire
    private PermissionCheck permissionCheck;       // and it uses @MockBean dependency

    @MockBean                                      // if no such @MockBean exists
    private MyEntityRepository myEntityRepository; // the real implementation is used

    @Test
    public void shouldHasPermission() {
        MyEntity myEntity = new MyEntity();

        when(this.myEntityRepository.findById(any())).thenReturn(myEntity);
        assertTrue(this.permissionCheck.hasPermission(0));
    }
}

 类似资料:
  • 有几个很好的博客关于如何使用泛型类实现存储库模式和工作单元模式。 使用实体框架6.1实现数据访问层 实现存储库和工作单元模式 这个想法是,定义一个通用接口IRepository和一个隐藏数据实际访问方式的类存储库。可以使用实体框架DbContext来访问它,或者存储库可能是用于单元测试的内存集合。 我经常看到添加了几个与Queryable和/或Enumerable函数类似的Query函数。 例如,

  • 我试图测试一个服务方法,但为了做到这一点,我必须模拟我的ReportRepository。除了对Include方法的调用使模拟返回为NULL外,其他操作都很好。 下面返回预期的报告: 但该服务实际上执行以下操作: 问题是,当我在模拟中包含'include'方法时,返回的是null而不是预期的报告,因此我的测试以:

  • 我有下面的课,我试图测试。我遇到问题的方法是,因为我试图存根/模拟行为,然后在测试中验证行为。

  • 我使用导航组件并在一个RecolyerView(MVVM架构,所以这个片段有一个viewmodel)中加载数据,如果我移动到另一个片段,然后导航回到有viewmodel的片段,那么viewmodel的livedata是空的,但我不知道为什么。如果我正确地知道,我就不需要手动调用来持久化数据,因为无论如何都会这样做。我将对象存储在livedata中,并且该类是extends Parcelable。

  • 我已经创建了一个包含控制器、服务和存储库层的基本Rest API。我现在正在尝试为通过产品ID查找产品的服务层方法编写一个单元测试。但是,当我运行测试时,它会在我试图模拟存储库findById()方法的行中抛出一个NullPointerException。 服务层中的getProductById()方法如下所示: 我的服务层测试类:

  • 简而言之,我试图创建一个简单的api,它将返回具有匹配ID的用户。我使用postman向使用Node.js和Express创建的本地主机发送请求。当我请求第一个用户时,它工作得很好,但当请求“john”时,它会抛出一个错误。我正在编写一门udemy课程的代码,但除了材料过时之外,我不知道问题是什么。错误为“错误[ERR_HTTP_HEADERS_SEND]:将标头发送到客户端后无法设置标头” nu