英文:
Why bean is not initialized when used @MockBean annotation in unit test
问题
我有一个非常糟糕的bean实现
@Component
public class Repository{
public List<String> people = new ArrayList<>();
我还有一个测试,在测试中我用一个模拟(mock)替换了repository。但是当我试图通过repository模拟访问测试中的"people"字段时,我会得到NullPointerException。
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MainControllerTest{
@Autowired
private MockMvc mockMvc;
@MockBean
private Repository repository;
@Test
public void someTest(){
repository.people // null -> NullPointerException
}
}
为什么会发生这种情况?bean是否在最初被初始化了?对于这种糟糕的实现,什么是正确的解决方案?
<details>
<summary>英文:</summary>
I have a very bad bean implementation
@Component
public class Repository{
public List<String> people= new ArrayList<>();
And I also have a test where I replace the repository with a mock.
But when I try to access the "people" field in the test via the repository mock i get NullPointerException
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MainControllerTest{
@Autowired
private MockMvc mockMvc;
@MockBean
private Repository repository;
@Test
public void someTest(){
repository.people // null -> NullPointerException
}
}
Why it happens? Is the bean initialized initially or not? What's the correct solution with such a bad implementation?
</details>
# 答案1
**得分**: 3
Bean initialized as it suppose to be with `@MockBean`.
它会按照预期使用`@MockBean`进行初始化。
It produces just a stub for you. All nested stuff of the `Repository` class is ignored.
它只为您生成一个存根。 `Repository`类的所有嵌套内容都会被忽略。
In your case you have a completely initialized mock. But of course it's nested fields are null. Becase it is a mock and nested fields will not be initialized. Mock assumes that you just need kind of wrapper of that particular class to mock some behavior on that.
在您的情况下,您拥有一个完全初始化的模拟对象。但是当然它的嵌套字段为空。因为它是一个模拟对象,并且不会初始化嵌套字段。模拟对象假设您只需要某种包装器来模拟该特定类上的某些行为。
What you need to do is to change `@MockBean` to the `@SpyBean`.
您需要做的是将`@MockBean`更改为`@SpyBean`。
In that case your class fields would be initialized as it defined in your `Repository` class. So, you will have a real `Repository` object but wrapped with Mockito Spy.
在这种情况下,您的类字段将按照`Repository`类中的定义进行初始化。因此,您将拥有一个真正的`Repository`对象,但包装在Mockito Spy中。
And it will allow you to perform all testing manipulations on that object that needed.
这将允许您对该对象执行所有所需的测试操作。
<details>
<summary>英文:</summary>
Bean initialized as it suppose to be with `@MockBean`.
It produces just a stub for you. All nested stuff of the `Repository` class is ignored.
In your case you have a completely initialized mock. But of course it's nested fields are null. Becase it is a mock and nested fields will not be initialized. Mock assumes that you just need kind of wrapper of that particular class to mock some behavior on that.
What you need to do is to change `@MockBean` to the `@SpyBean`.
In that case your class fields would be initialized as it defined in your `Repository` class. So, you will have a real `Repository` object but wrapped with Mockito Spy.
And it will allow you to perform all testing manipulations on that object that needed.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论