繁体   English   中英

Mockito + JUnit 测试返回 NullPointerException

[英]Mockito + JUnit test returns a NullPointerException

我正在尝试模拟课程,但我一直在获得 NPE。 我看过这篇文章Mockito - NullpointerException when stubbing Method 在这篇文章中,他们解释了这一点:

"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(...)."

我几乎可以肯定这也适用于我的问题。 但我找不到解决方案。 我现在已经尝试了将近10个小时。

我还阅读了一些关于@Autowired 和@Before 的内容,显然@autowired 是在@before 之前创建的,这也可以解释我的NPE。

NPE 被抛出@Test void getPlantSpeciesById,因为 foundPlantSpecies 是 null 和 plantSpeciesServiceMock.getPlanySpeciesById(1)。 感觉就像@Before 根本没有运行。

对不起,如果我遗漏了什么,我现在真的很累,但我正在拼命寻找解决方案。

这是我的代码:

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

}

首先@SpringBootTest用于集成测试,而MockitoJunitRunner用于单元测试——你永远不应该混合它们。 区别很关键...

看起来您正在尝试在这里进行单元测试,所以请尝试删除@SpringBootTest和其他注释 - 基本上除了 mockito runner 之外的所有内容。

在这一步之后,测试不会尝试启动 spring 上下文,并且在技术上将成为单元测试

现在,在这一步之后,将@MockBean更改为@Mock 仅当您的测试使用 spring 运行时,使用@MockBean才有意义,而@Mock是 mockito 运行器所采用的注释

在这一步之后,您应该停下来并了解您到底想测试什么——这里的单位是什么? 服务? 看起来像那样,但是 - 你应该用new创建一个服务实例并调用真正的方法,在你试图在模拟上调用方法的问题中,这在逻辑上听起来不正确......

最重要的是,我建议从正确理解如何编写单元测试(有或没有 mockito)开始,然后再深入研究 spring 启动的复杂但强大的集成测试框架。 抱歉,如果答案似乎不清楚,但我觉得问题中的代码中有太多看起来错误的东西,所以 IMO 无法用一两行代码来回答这个问题。

不要嘲笑正在测试的内容。 只是依赖关系。

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

}

然后

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

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

现在

Tulip result = underTest.foo;

assertEquals(result, tulip);

这样的事情应该可以完成工作。 快乐编码。

暂无
暂无

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

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