NullPointerException在injectedMock中。

huangapple go评论102阅读模式
英文:

NullPointerException in injectedMock

问题

以下是您要翻译的内容:

  1. 我有一个Rest控制器需要进行测试
  2. import javax.validation.Valid;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.http.HttpStatus;
  5. import org.springframework.http.ResponseEntity;
  6. import org.springframework.web.bind.annotation.RestController;
  7. @RestController
  8. public class PetController implements PetApi {
  9. @Autowired
  10. PetRepository pr;
  11. @Override
  12. public ResponseEntity<Pet> addPet(@Valid Pet pet) {
  13. pr.save(new PetBE(9L, "dummy"));
  14. return new ResponseEntity<Pet>(pet, HttpStatus.OK);
  15. }
  16. }
  17. import org.springframework.data.repository.CrudRepository;
  18. public interface PetRepository extends CrudRepository<PetBE, Long> {
  19. }
  20. 我想要模拟`PetRepository`并测试传入的对象是否与返回的对象相同
  21. import static org.junit.jupiter.api.Assertions.*;
  22. import org.junit.jupiter.api.Test;
  23. import org.mockito.InjectMocks;
  24. import org.springframework.boot.test.context.SpringBootTest;
  25. import org.springframework.boot.test.mock.mockito.MockBean;
  26. import org.springframework.http.HttpStatus;
  27. import org.springframework.http.ResponseEntity;
  28. import com.example.petstore.backend.api.model.Pet;
  29. import com.example.petstore.backend.db.PetRepository;
  30. import com.example.petstore.backend.db.PetBE;
  31. import static org.mockito.Mockito.when;
  32. import static org.mockito.ArgumentMatchers.any;
  33. import static org.mockito.AdditionalAnswers.returnsFirstArg;
  34. @SpringBootTest
  35. public class PetControllerTest {
  36. @InjectMocks
  37. private PetController petController;
  38. @MockBean
  39. private PetRepository pr;
  40. @Test
  41. void testAddPet() {
  42. when(pr.save(any(PetBE.class))).then(returnsFirstArg());
  43. Pet p1 = new Pet().id(5L).name("Klaus");
  44. assertNotNull(petController);
  45. /*L35*/ ResponseEntity<Pet> r = petController.addPet(p1);
  46. assertEquals(new ResponseEntity<Pet>(p1, HttpStatus.OK), r);
  47. }
  48. }
  49. 当我将此方法作为Gradle测试运行时我得到了以下错误消息
  50. com.example.petstore.backend.api.implementation.PetControllerTest > testAddPet() FAILED
  51. java.lang.NullPointerException at PetControllerTest.java:35

此处提供的翻译内容应该满足您的要求。如果您有任何其他问题或需要进一步的帮助,请随时提问。

英文:

I have a RestController that I want to test:

  1. import javax.validation.Valid;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.http.HttpStatus;
  4. import org.springframework.http.ResponseEntity;
  5. import org.springframework.web.bind.annotation.RestController;
  6. @RestController
  7. public class PetController implements PetApi {
  8. @Autowired
  9. PetRepository pr;
  10. @Override
  11. public ResponseEntity&lt;Pet&gt; addPet(@Valid Pet pet) {
  12. pr.save(new PetBE(9L, &quot;dummy&quot;));
  13. return new ResponseEntity&lt;Pet&gt;(pet, HttpStatus.OK);
  14. }
  15. }
  1. import org.springframework.data.repository.CrudRepository;
  2. public interface PetRepository extends CrudRepository&lt;PetBE, Long&gt; {
  3. }

I want to mock PetRepository and test if the object passed is the object returned:

  1. import static org.junit.jupiter.api.Assertions.*;
  2. import org.junit.jupiter.api.Test;
  3. import org.mockito.InjectMocks;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. import org.springframework.boot.test.mock.mockito.MockBean;
  6. import org.springframework.http.HttpStatus;
  7. import org.springframework.http.ResponseEntity;
  8. import com.example.petstore.backend.api.model.Pet;
  9. import com.example.petstore.backend.db.PetRepository;
  10. import com.example.petstore.backend.db.PetBE;
  11. import static org.mockito.Mockito.when;
  12. import static org.mockito.ArgumentMatchers.any;
  13. import static org.mockito.AdditionalAnswers.returnsFirstArg;
  14. @SpringBootTest
  15. public class PetControllerTest {
  16. @InjectMocks
  17. private PetController petController;
  18. @MockBean
  19. private PetRepository pr;
  20. @Test
  21. void testAddPet() {
  22. when(pr.save(any(PetBE.class))).then(returnsFirstArg());
  23. Pet p1 = new Pet().id(5L).name(&quot;Klaus&quot;);
  24. assertNotNull(petController);
  25. /*L35*/ ResponseEntity&lt;Pet&gt; r = petController.addPet(p1);
  26. assertEquals(new ResponseEntity&lt;Pet&gt;(p1, HttpStatus.OK), r);
  27. }
  28. }

When I run this method as a gradle test, I get

  1. com.example.petstore.backend.api.implementation.PetControllerTest &gt; testAddPet() FAILED
  2. java.lang.NullPointerException at PetControllerTest.java:35

which is petController.addPet(p1);.

My printlns 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

  1. @BeforeAll
  2. public void setup() {
  3. MockitoAnnotations.initMocks(this);
  4. }

because it was suggested here but that gave an InitializationException:

  1. com.example.petstore.backend.api.implementation.PetControllerTest &gt; initializationError FAILED
  2. 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扩展。像这样:

  1. import static org.junit.jupiter.api.Assertions.*;
  2. import org.junit.jupiter.api.Test;
  3. import org.mockito.InjectMocks;
  4. import org.mockito.Mock;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.http.ResponseEntity;
  7. import com.example.petstore.backend.api.model.Pet;
  8. import com.example.petstore.backend.db.PetRepository;
  9. import com.example.petstore.backend.db.PetBE;
  10. import static org.mockito.Mockito.when;
  11. import static org.mockito.ArgumentMatchers.any;
  12. import static org.mockito.AdditionalAnswers.returnsFirstArg;
  13. @ExtendWith(MockitoExtension.class)
  14. public class PetControllerTest {
  15. @InjectMocks
  16. private PetController petController;
  17. @Mock
  18. private PetRepository pr;
  19. @Test
  20. void testAddPet() {
  21. when(pr.save(any(PetBE.class))).then(returnsFirstArg());
  22. Pet p1 = new Pet().id(5L).name("Klaus");
  23. assertNotNull(petController);
  24. ResponseEntity<Pet> r = petController.addPet(p1);
  25. assertEquals(new ResponseEntity<Pet>(p1, HttpStatus.OK), r);
  26. }
  27. }

编辑: 如果你不想使用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:

  1. import static org.junit.jupiter.api.Assertions.*;
  2. import org.junit.jupiter.api.Test;
  3. import org.mockito.InjectMocks;
  4. import org.mockito.Mock;
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.http.ResponseEntity;
  7. import com.example.petstore.backend.api.model.Pet;
  8. import com.example.petstore.backend.db.PetRepository;
  9. import com.example.petstore.backend.db.PetBE;
  10. import static org.mockito.Mockito.when;
  11. import static org.mockito.ArgumentMatchers.any;
  12. import static org.mockito.AdditionalAnswers.returnsFirstArg;
  13. @ExtendWith(MockitoExtension.class)
  14. public class PetControllerTest {
  15. @InjectMocks
  16. private PetController petController;
  17. @Mock
  18. private PetRepository pr;
  19. @Test
  20. void testAddPet() {
  21. when(pr.save(any(PetBE.class))).then(returnsFirstArg());
  22. Pet p1 = new Pet().id(5L).name(&quot;Klaus&quot;);
  23. assertNotNull(petController);
  24. ResponseEntity&lt;Pet&gt; r = petController.addPet(p1);
  25. assertEquals(new ResponseEntity&lt;Pet&gt;(p1, HttpStatus.OK), r);
  26. }
  27. }

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.

huangapple
  • 本文由 发表于 2020年10月11日 20:09:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/64303841.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定