为什么在单元测试中使用 @MockBean 注解时,bean没有被初始化?

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

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&lt;String&gt; people= new ArrayList&lt;&gt;();
And I also have a test where I replace the repository with a mock.
But when I try to access the &quot;people&quot; 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 -&gt; NullPointerException
        }
    }
Why it happens? Is the bean initialized initially or not? What&#39;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&#39;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&#39;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>



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

发表评论

匿名网友

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

确定