injectedMock 中的 NullPointerException

NullPointerException in injectedMock

我有一个要测试的 RestController:

import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PetController implements PetApi {
    
    @Autowired
    PetRepository pr;
    
    @Override
    public ResponseEntity<Pet> addPet(@Valid Pet pet) {
        pr.save(new PetBE(9L, "dummy"));
        return new ResponseEntity<Pet>(pet, HttpStatus.OK);
    }

}
import org.springframework.data.repository.CrudRepository;

public interface PetRepository extends CrudRepository<PetBE, Long> {
}

我想模拟 PetRepository 并测试传递的对象是否是返回的对象:

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import com.example.petstore.backend.api.model.Pet;
import com.example.petstore.backend.db.PetRepository;
import com.example.petstore.backend.db.PetBE;

import static org.mockito.Mockito.when;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.AdditionalAnswers.returnsFirstArg;

@SpringBootTest
public class PetControllerTest {

    @InjectMocks
    private PetController petController;

    @MockBean
    private PetRepository pr;   

    @Test
    void testAddPet() {
        when(pr.save(any(PetBE.class))).then(returnsFirstArg());
        Pet p1 = new Pet().id(5L).name("Klaus");
        assertNotNull(petController);
/*L35*/ ResponseEntity<Pet> r = petController.addPet(p1);
        assertEquals(new ResponseEntity<Pet>(p1, HttpStatus.OK), r);
    }
}

当我运行这个方法作为gradle测试时,我得到

com.example.petstore.backend.api.implementation.PetControllerTest > testAddPet() FAILED
    java.lang.NullPointerException at PetControllerTest.java:35

也就是 petController.addPet(p1);.

我在 addPet 中的 println 没有显示,我不能在那里设置任何断点,因为它被模拟了。 addPet 中唯一可能为 null 的引用是 pr,但当我使用 curl 发送请求时它工作正常。
我也试过添加

    @BeforeAll
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

因为有人建议 here 但这给出了 InitializationException:

com.example.petstore.backend.api.implementation.PetControllerTest > initializationError FAILED
    org.junit.platform.commons.JUnitException at LifecycleMethodUtils.java:57

我该如何调试它?
我怎样才能让它工作?

您在这里混合了来自各种测试框架的注释。如果您希望使用 Mockito 注释 @InjectMocks 那么我建议您根本不要使用任何 Spring-related 模拟注释,而是使用 @Mock 注释来创建您想要的 bean 的模拟版本注入(进入 @InjectMocks-注释字段)。还要确保 bootstrap Mockito 扩展 @ExtendWith(MockitoExtension.class)。类似于:

import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import com.example.petstore.backend.api.model.Pet;
import com.example.petstore.backend.db.PetRepository;
import com.example.petstore.backend.db.PetBE;

import static org.mockito.Mockito.when;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.AdditionalAnswers.returnsFirstArg;

@ExtendWith(MockitoExtension.class)
public class PetControllerTest {

    @InjectMocks
    private PetController petController;

    @Mock
    private PetRepository pr;

    @Test
    void testAddPet() {
        when(pr.save(any(PetBE.class))).then(returnsFirstArg());
        Pet p1 = new Pet().id(5L).name("Klaus");
        assertNotNull(petController);
        ResponseEntity<Pet> r = petController.addPet(p1);
        assertEquals(new ResponseEntity<Pet>(p1, HttpStatus.OK), r);
    }
}

编辑: 在内部调用 MockitoAnnotations.initMocks(this) 例如,如果您不想使用 [=17=,则需要 @BeforeEach-注释方法].它们本质上是相同的东西,但在 JUnit Jupiter 中没那么必要,因为您可以使用多个扩展来扩展测试 class,这在 JUnit 4.x 中是不可能的。因此,如果您想 bootstrap 使用 Spring 上下文 Mockito 进行测试,那么您必须选择其中一个并自己设置另一个。