简体   繁体   English

Mockito + JUnit 测试返回 NullPointerException

[英]Mockito + JUnit test returns a NullPointerException

I am trying to Mock classes but i keep getting a NPE.我正在尝试模拟课程,但我一直在获得 NPE。 I've seen this post Mockito - NullpointerException when stubbing Method .我看过这篇文章Mockito - NullpointerException when stubbing Method In this post they explain this:在这篇文章中,他们解释了这一点:

"The default return value of methods you haven't stubbed yet is false for boolean methods, an empty collection or map for methods returning collections or maps and null otherwise. This also applies to method calls within when(...)." "The default return value of methods you haven't stubbed yet is false for boolean methods, an empty collection or map for methods returning collections or maps and null otherwise. This also applies to method calls within when(...)."

I am almost certain that this applies to my problem as well.我几乎可以肯定这也适用于我的问题。 But i can not find a solution for it.但我找不到解决方案。 I've been trying for almost 10 hours right now.我现在已经尝试了将近10个小时。

Also i read something about @Autowired and @Before, apparently @autowired is created before @before, this could also explain my NPE.我还阅读了一些关于@Autowired 和@Before 的内容,显然@autowired 是在@before 之前创建的,这也可以解释我的NPE。

The NPE is thrown at the @Test void getPlantSpeciesById, because foundPlantSpecies is null and so is plantSpeciesServiceMock.getPlanySpeciesById(1). NPE 被抛出@Test void getPlantSpeciesById,因为 foundPlantSpecies 是 null 和 plantSpeciesServiceMock.getPlanySpeciesById(1)。 It feels like @Before is not run at all.感觉就像@Before 根本没有运行。

Excuse me, if i am missing something, i am really tired at the moment but i am desperately searching for a solution.对不起,如果我遗漏了什么,我现在真的很累,但我正在拼命寻找解决方案。

Here is my Code:这是我的代码:

@SpringBootTest(classes = PlantSpeciesService.class)
@Import({TestConfig.class})
@RunWith(MockitoJUnitRunner.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class PlantSpeciesServiceTest {

@MockBean
private PlantSpeciesRepository plantSpeciesRepository;

@MockBean
private ModelMapper modelMapper;

@Autowired
private PlantSpeciesService plantSpeciesServiceMock;

@Before("com.oopa.domain.services.PlantSpeciesService")
public void setup() {
    MockitoAnnotations.initMocks(this);
    PlantSpecies tulip = new PlantSpecies();
    tulip.setId(1);
    tulip.setMinHumidity(200);
    tulip.setMaxHumidity(400);
    tulip.setName("Tulip");



    Mockito.when(plantSpeciesRepository.findById(tulip.getId())).thenReturn(
            Optional.of(this.modelMapper.map(tulip, com.oopa.dataAccess.model.PlantSpecies.class))
    );
}

@Test
void getPlantSpeciesById() {
    PlantSpecies foundPlantSpecies = plantSpeciesServiceMock.getPlantSpeciesById(1);

    System.out.println(plantSpeciesServiceMock.getPlantSpeciesById(1));
    System.out.println(foundPlantSpecies);
    System.out.println();
    assertEquals("Tulip", foundPlantSpecies.getName());
}

} }

First things first @SpringBootTest is used for integration testing, while MockitoJunitRunner is for unit testing - and you should never mix them.首先@SpringBootTest用于集成测试,而MockitoJunitRunner用于单元测试——你永远不应该混合它们。 The difference is crucial...区别很关键...

It looks like you're trying to do unit testing here, so please try to remove @SpringBootTest and other annotations - basically everything but mockito runner.看起来您正在尝试在这里进行单元测试,所以请尝试删除@SpringBootTest和其他注释 - 基本上除了 mockito runner 之外的所有内容。

After this step, the test wont try to start the spring context and will technically become a unit test在这一步之后,测试不会尝试启动 spring 上下文,并且在技术上将成为单元测试

Now, after this step, change @MockBean to @Mock .现在,在这一步之后,将@MockBean更改为@Mock Using @MockBean makes sense only if your test runs with spring while @Mock is the annotation honored by the mockito runner仅当您的测试使用 spring 运行时,使用@MockBean才有意义,而@Mock是 mockito 运行器所采用的注释

After this step you should stop and understand what exactly would you like to test - what is the unit here?在这一步之后,您应该停下来并了解您到底想测试什么——这里的单位是什么? A service?服务? It looks like that but then - you should create an instance of the service with new and call the real method, in the question you're trying to call the method on mock, which does not sound right logically....看起来像那样,但是 - 你应该用new创建一个服务实例并调用真正的方法,在你试图在模拟上调用方法的问题中,这在逻辑上听起来不正确......

Bottom line I suggest to start off with proper understanding of how to write unit tests (with or without mockito) and only after that delve into the complicated but powerful integration testing framework of spring boot here.最重要的是,我建议从正确理解如何编写单元测试(有或没有 mockito)开始,然后再深入研究 spring 启动的复杂但强大的集成测试框架。 Sorry if the answer seems unclear but I feel like there are too many things in the code in the question that look wrong so the question IMO cant be answered with one or two lines of code.抱歉,如果答案似乎不清楚,但我觉得问题中的代码中有太多看起来错误的东西,所以 IMO 无法用一两行代码来回答这个问题。

Do not mock what is being tested.不要嘲笑正在测试的内容。 Just the dependencies.只是依赖关系。

class PlantSpeciesServiceTest {

@Mock
private PlantSpeciesRepository mockedPlantSpeciesRepository;

@Mock
private ModelMapper modelMapper;

private PlantSpeciesService underTest;


public void setup() {
    init(this);
    underTest = new PlantSpeciesService(mockedPlantSpeciesRepository);

  /*You might need this (sometimes you will)*/
  //mockedPlantSpeciesRepository = mock(PlantSpeciesRepository.class);

}

Then然后

  PlantSpecies tulip = new PlantSpecies();
    tulip.setId(1);
    tulip.setMinHumidity(200);
    tulip.setMaxHumidity(400);
    tulip.setName("Tulip");

when(underTest.foo).thenReturn(tulip); when(underTest.foo).thenReturn(tulip);

Now现在

Tulip result = underTest.foo;

assertEquals(result, tulip);

Something like this should get the job done.这样的事情应该可以完成工作。 Happy coding.快乐编码。

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

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