提问者:小点点

injectedMock中的NullPointerException


我有一个我想测试的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不显示,我无法在那里设置任何断点,因为它被mock了。addPet中唯一可以为空的引用是pr,但当我使用curl发送请求时它可以正常工作。
我还尝试添加

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

因为它是在这里建议的,但它给出了一个初始化异常:

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

我如何调试这个?
我如何才能让它工作?


共1个答案

匿名用户

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

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),例如,如果您不想使用MockitoExency,则需要使用@Before各注释方法。它们本质上是相同的,但在JUnit Jupiter中不太必要,因为您可以扩展具有多个扩展的测试类,这在JUnit 4.x中是不可能的。因此,如果您想使用Spring上下文和Mockito引导测试,那么您必须选择其中一个并自己设置另一个。