【问题标题】:Spring Boot API test throwing nullPointerExceptionSpring Boot API 测试抛出 nullPointerException
【发布时间】:2022-01-04 10:54:21
【问题描述】:

所以我正在尝试测试我的 api,当我尝试使用存储库时它给了我一个空指针异常。

假设我的 application.yml(inside test/resources) 中有一个用于测试的 h2 数据库,如下所示:

spring:
  profiles:
    active: test
  datasource:
    username:
    password:
    url: jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE;
    platform: h2

这是我的 ControllerAPItest.java

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureTestDatabase
class ControllerAPITest {



    @Mock
    CompaniaRepository companiaRepository;
    @Mock
    DefaultGroupRepository defaultGroupRepository;
    @Mock
    OfficeRepository officeRepository;

    @InjectMocks
    CompaniaServiceImpl companiaService;

    ControllerAPI controllerAPI = new ControllerAPI(companiaService);



    @BeforeEach
    void setUp() {
        Compania compania = new Compania();
        compania.setName("companiaTest");
        compania.setDominio("dominioTest");
        compania.setAltas("altasTest");
        compania.setBajas("bajasTest");
        compania.setDefault_group(null);
        compania.setOffice(null);

        companiaRepository.save(compania);
    }

    @AfterEach
    void tearDown() {
        companiaRepository.deleteAll();
    }

    @Test
    void getByField() {
    }

    @Test
    void getCompanias() {
        System.out.println(controllerAPI.GetCompanias());
    }
}

这是我得到的错误的输出:

java.lang.NullPointerException 在 控制器.ControllerAPI.GetCompanias(ControllerAPI.java:114) 在 controller.ControllerAPITest.getCompanias(ControllerAPITest.java:65)

它指向的行是:

companiaRepository.save(compania);

这是完整的错误:https://textdoc.co/eGmu72wa1ydEoJ4T

我的代码发生了什么?

谢谢!

编辑。这是我的控制器中的 getCompanias。

@ResponseStatus(HttpStatus.OK)
    @GetMapping()
    public Map<String, List<Compania>> GetCompanias() {
        Map<String, List<Compania>> mappedResult = Collections.singletonMap("result", companiaService.getCompanias());
        return mappedResult;
        // return companiaService.getCompanias();
    }

这里使用了companiaService:

public List<Compania> getCompanias() {
        return companiaRepository.findAll();
    }

谢谢!

【问题讨论】:

  • 在您创建controllerAPI 时,尚未创建companiaService。在@Before 方法中创建controllerAPI
  • @tgdavies 不,但还是谢谢!我认为与模拟它没有实例化它或类似的东西有关:S
  • 您需要在问题中的 controller.ControllerAPI.GetCompanias(ControllerAPI.java:114) 处显示代码。
  • @tgdavies 我已经编辑了我的问题,谢谢!

标签: java spring-boot api testing mocking


【解决方案1】:

测试设置有很多问题,我的建议是通读 mockito 和 spring 测试基础知识,例如 herehere

测试设置
对于初学者来说,代码混合了不同的测试设置。注释 @RunWith(SpringRunner.class) 建议使用 JUnit4 设置,但 strack 跟踪指示使用 JUnit5,因为 jupiter 包位于类路径 (org.junit.jupiter.engine.execution....) 上。 @RunWith 可以删除,因为 JUnit5 依赖于扩展,并且弹簧扩展 (@ExtendWith(SpringExtension.class)) 已经作为元注释出现在 @SpringBootTest 注释 (source) 中。

模拟注释的使用
当您计划创建 Spring 启动测试时,可以使用 @MockBean 注释在 TestApplicationContext 中注入模拟。但是,通过将@Mock@InjectMocks 一起使用,模拟将仅由Mockito 创建,而无需在应用程序上下文中注册。有关差异的更多信息可以找到here

模拟准备
模拟是类的“假”实现,用于模仿真实对象的行为。它不是一个真实的对象,它只执行您分配给它的任务。然而,在 setup() 中,该方法尝试将模拟作为真实对象进行访问。这不起作用,因为它不是设置模拟的正确方法:

    // The CompaniaRepository is annotated as being a mock
    @Mock
    CompaniaRepository companiaRepository;
    ...

    @BeforeEach
    void setUp() {
        Compania compania = new Compania();
        ...

        // Here a method on the mock is invoked, which has no use
        companiaRepository.save(compania);
    }

有关设置 Mockito 模拟的更多信息,请访问 here

此外,如果您计划设置数据库测试,我不建议模拟存储库,因为它减少了使用数据库的要求(假设没有第三个存储库确实需要 H2)。

最后一件事; Spring 控制器最好通过 Web 层执行测试来进行测试。使用new ControllerApi(...) 实例化被测控制器只会测试方法,而不是它们映射到的端点。可以在here 找到有关如何测试 Web 层的精彩教程。

【讨论】:

    猜你喜欢
    • 2018-11-12
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 2018-06-27
    • 1970-01-01
    • 2023-03-25
    • 2017-04-23
    • 1970-01-01
    相关资源
    最近更新 更多