简体   繁体   English

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

[英]Why @MockBean does not mock my target repository class (returns null)?

Here is the class I want to test这是我要测试的 class

@Component
public class PermissionCheck {

    @Autowired
    private MyEntityRepository myEntityRepository;

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

Here is the test class这里是测试 class

@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));
    }
}

And when I run this test I got当我运行这个测试时,我得到了

java.lang.NullPointerException
    at PermissionCheck.hasPermission(PermissionCheck.java:line1)
    at PermissionCheckTests.shouldHasPermission(PermissionCheckTests.java:line2)

In the above, line1 and line2 refer to these two lines上面的line1和line2指的是这两行

        MyEntity myEntity = myEntityRepository.findById(myEntityId);
        assertTrue(this.permissionCheck.hasPermission(0));

And using debugger I see that when entering PermissionCheck.hasPermission from PermissionCheckTests.shouldHasPermission , the repository field并使用调试器,我看到当从PermissionCheckTests.shouldHasPermission输入PermissionCheck.hasPermission时,存储库字段

    @Autowired
    private MyEntityRepository myEntityRepository;

is null.是 null。

I created these classes by referring to others existing codes, from different places, and without really understanding how to the annotations (partially due to running out of time), so if someone can tell me not only how to fix, but also why I'm wrong, I would really appreciate it!我通过引用来自不同地方的其他现有代码来创建这些类,并且没有真正理解如何注释(部分原因是时间不多了),所以如果有人不仅可以告诉我如何修复,还可以告诉我为什么我错了,我真的很感激!

Edit:编辑:

I made the change suggested by @Nikolas Charalambidis (thank you,), so my PermissionCheck class now looks exactly like我做了@Nikolas Charalambidis 建议的更改(谢谢,),所以我的PermissionCheck class 现在看起来完全一样

@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));
    }
}

But I then got the following exception但后来我得到了以下异常

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="")}

With a little bit search, from this SO answer , I feel like I should not @Autowired PermissionCheck , since it is a class, not an interface.通过一些搜索,从这个 SO 答案,我觉得我不应该 @Autowired PermissionCheck ,因为它是 class,而不是接口。

Does that mean I have to create an interface, @Autowired it and let PermissionCheck implement it?这是否意味着我必须创建一个接口,@Autowired 并让PermissionCheck实现它? It seems redundant to me, since I don't see why I need such an interface.这对我来说似乎是多余的,因为我不明白为什么我需要这样的界面。 Is there a way to make it work without creating a new interface which I will solely use for this purpose?有没有办法让它工作而无需创建我将仅用于此目的的新界面?

The instance of class PermissionCheck is not properly injected. class PermissionCheck的实例未正确注入。 The tests use the Spring container in the same way as the production code.测试以与生产代码相同的方式使用 Spring 容器。 The following line would not inject the myEntityRepository .以下行不会注入myEntityRepository

this.permissionCheck = new PermissionCheck();

Spring: NullPointerException occurs when including a bean partly answers your question. Spring:包含 bean 部分回答您的问题时发生 NullPointerException You need to @Autowire the thing.你需要@Autowire的东西。

The Spring test context is no different. Spring 测试环境也不例外。 As long as @MockBean MyEntityRepository exists as a mocked bean, the PermissionCheck will be autowired in the standard way using the mocked class in precedence over the existing bean in the test scope .只要@MockBean MyEntityRepository作为模拟 bean 存在, PermissionCheck就会以标准方式自动装配,使用模拟的 class优先于测试 scope 中的现有 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));
    }
}

in my case i was using lombok i was added @NoArgsConstructor to the class that that i had injected my repository.在我的情况下,我使用的是 lombok,我将 @NoArgsConstructor 添加到了我注入我的存储库的 class 中。

@Component
@AllArgsConstructor
@NoArgsConstructor // what cuased the null pointer
public class ParcelUtil {

    private final Logger log = LoggerFactory.getLogger(OrderEventConsumer.class);

    private ParcelRepository parcelRepository;

}

my test:我的测试:

 @SpringBootTest
    @DirtiesContext
    public class OrderEventConsumerTest extends SpringBootEmbeddedKafka {
        @MockBean
        private ParcelRepository parcelRepository;
    
    }

   

    @Test
        public void update_parcel_inride_to_delivered_nxb() throws JsonProcessingException {
    
            //given
            List<Parcel> parcels = DataUtil.createParcel_inride_and_draft_nxb();
                Mockito
.when(parcelRepository.findFirstByParcelGroupId("12"))
.thenReturn(Optional.ofNullable(parcels.get(0))); //where i got null pointer
 

   
    
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM