测试服务时JUnit5 SpringBootTest NullPointerException

JUnit5 SpringBootTest NullPointerException when testing Service

我正在学习对服务进行单元测试的教程,我正在尝试使用 JUnit5 而不是 JUnit4(教程使用的是 JUnit4)。当我完全按照 JUnit4 的教程进行测试时,测试工作正常,但我得到了 JUnit5 的 NullPointerException。

存储库:

public interface CourseRepo extends CrudRepository<Course, Long> {}

服务:

@Service
public class CourseService {

    private final CourseRepo courseRepo;

    public CourseService(CourseRepo courseRepo) {
        this.courseRepo = courseRepo;
    }

    public Course save(Course course) {
        Course newCourse = courseRepo.save(course);
        return newCourse;
    }

}

测试:

package com.elovell.blackboard.service;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import com.elovell.blackboard.domain.Course;
import com.elovell.blackboard.repository.CourseRepo;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;

@ExtendWith(MockitoExtension.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
public class CourseServiceTest {

    @Mock
    public CourseRepo courseRepo;

    @InjectMocks
    public CourseService courseService;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testSaveCourse() {

        Course mockCourse = new Course();
        mockCourse.setPk1(1L);
        mockCourse.setCourseId("ENGL101");

        when(courseRepo.save(any(Course.class))).thenReturn(mockCourse);
        // save(null) should still return mockCourse
        Course newCourse = courseService.save(null);
        assertEquals("ENGL101", newCourse.getCourseId());
    }
}

这是异常的前几行:

java.lang.NullPointerException
    at com.elovell.blackboard.service.CourseServiceTest.testSaveCourse(CourseServiceTest.java:44)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

我的构建文件的测试和依赖部分:

test {
    useJUnitPlatform {
        includeEngines 'junit-jupiter'
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    runtimeOnly 'com.h2database:h2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.5.1")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.1.0")
    testCompile 'org.mockito:mockito-junit-jupiter:2.23.4'
}

您似乎在尝试将集成测试与单元测试混合使用。

当您使用 @SpringBootTest 注释时,Junit5 的 SpringExtension 在 运行 您的测试之前启动应用程序上下文,并且要在测试中进行模拟,您需要使用 @MockBean 注释而不是 @Mock & @InjectMocks。这是不同范围的测试。

如我所见,您只需要一个单元测试,您可以删除 SpringBootTest 注释。

顺便说一下,我认为你在 when(courseRepo....any(Course.class) 获得了 NPE 尝试使用 isNull()any()(没有指定具体 class)。