英文:
NullPointerException in injectedMock
问题
以下是您要翻译的内容:
我有一个Rest控制器需要进行测试:
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
此处提供的翻译内容应该满足您的要求。如果您有任何其他问题或需要进一步的帮助,请随时提问。
英文:
I have a RestController that I want to test:
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> {
}
I want to mock PetRepository
and test if the object passed is the object returned:
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);
}
}
When I run this method as a gradle test, I get
com.example.petstore.backend.api.implementation.PetControllerTest > testAddPet() FAILED
java.lang.NullPointerException at PetControllerTest.java:35
which is petController.addPet(p1);
.
My println
s in addPet
are not displayed and I can't set any breakpoints there because it is mocked. The only reference in addPet
that could be null is pr
, but it works fine when I send a request with curl.
I've also tried adding
@BeforeAll
public void setup() {
MockitoAnnotations.initMocks(this);
}
because it was suggested here but that gave an InitializationException:
com.example.petstore.backend.api.implementation.PetControllerTest > initializationError FAILED
org.junit.platform.commons.JUnitException at LifecycleMethodUtils.java:57
How can I debug this?
How can I get this to work?
答案1
得分: 2
你混合了来自各种测试框架的注解。如果你想使用Mockito注解@InjectMocks
,我建议不使用任何与Spring相关的模拟注解,而是使用@Mock
注解来创建要注入的bean的模拟版本(注入到@InjectMocks
注解的字段中)。还要确保使用@ExtendWith(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);
}
}
编辑: 如果你不想使用MockitoExtension
,则在例如@BeforeEach
注解的方法内部调用MockitoAnnotations.initMocks(this)
是必要的。它们本质上是相同的,但在JUnit Jupiter中它不是那么必要,因为你可以将一个测试类扩展为多个扩展,而在JUnit 4.x中是不可能的。所以,如果你想要同时引导你的测试使用Spring上下文和Mockito,那么你必须选择其中一个并自己设置另一个。
英文:
You're mixing annotations from various testing frameworks here. If you wish to use the Mockito annotation @InjectMocks
then I'd recommend not using any Spring-related mocking annotations at all, but rather the @Mock
annotation to create a mocked version of the bean you want to inject (into the @InjectMocks
-annotated field). Also make sure you bootstrap the Mockito extension with @ExtendWith(MockitoExtension.class)
. Something like:
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);
}
}
EDIT: Calling MockitoAnnotations.initMocks(this)
inside for example a @BeforeEach
-annotated method is necessary if you don't want to use the MockitoExtension
. They're essentially the same thing, but it's less necessary in JUnit Jupiter because you can extend a test class with multiple extensions, which was not possible in JUnit 4.x. So if you wanted to bootstrap your test with both a Spring context and Mockito, then you had to pick one of them and setup the other one yourself.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论