Spring 启动 API 测试抛出 nullPointerException

Spring Boot API test throwing nullPointerException

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

据说我的 application.yml(在 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 at controller.ControllerAPI.GetCompanias(ControllerAPI.java:114) at 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();
    }

谢谢!

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

测试设置
对于初学者来说,代码混合了不同的测试设置。注释 @RunWith(SpringRunner.class) 建议使用 JUnit4 设置,但 strack trace 指示使用 JUnit5,因为 jupiter 包位于类路径中 (org.junit.jupiter.engine.execution....)。 @RunWith 可以删除,因为 JUnit5 依赖于扩展,并且 spring 扩展(@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(...) 实例化被测控制器将只测试方法,而不是它们映射到的端点。可以找到有关如何测试 Web 层的精彩教程 here