关于java:@ Mock,@ MockBean和Mockito.mock()之间的区别

Difference between @Mock, @MockBean and Mockito.mock()

创建测试和模拟依赖项时,这三种方法有什么区别?

  • @MockBean:

    1
    2
    @MockBean
    MyService myservice;
  • @嘲笑:

    1
    2
    @Mock
    MyService myservice;
  • Mockito.mock()

    1
    MyService myservice = Mockito.mock(MyService.class);

  • 普通Mockito库

    1
    2
    3
    4
    import org.mockito.Mock;
    ...
    @Mock
    MyService myservice;

    1
    2
    3
    import org.mockito.Mockito;
    ...
    MyService myservice = Mockito.mock(MyService.class);

    来自Mockito库,功能等效。
    它们允许模拟类或接口,并记录和验证其行为。

    使用注释的方式更短,因此更可取,并且通常是更可取的。

    请注意,要在测试执行期间启用Mockito批注,
    MockitoAnnotations.initMocks(this)静态方法必须被调用。
    为了避免测试之间的副作用,建议在每次测试执行之前先进行以下操作:

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

    启用Mockito批注的另一种方法是通过指定执行此任务的MockitoJUnitRunner以及其他有用的东西,用@RunWith注释测试类:

    1
    2
    @RunWith(org.mockito.runners.MockitoJUnitRunner.class)
    public MyClassTest{...}

    Spring Boot库包装Mockito库

    这确实是一个Spring Boot类:

    1
    2
    3
    4
    import org.springframework.boot.test.mock.mockito.MockBean;
    ...
    @MockBean
    MyService myservice;

    该类包含在spring-boot-test库中。

    它允许在Spring ApplicationContext中添加Mockito模拟。
    如果上下文中存在与声明的类兼容的bean,则将其替换为模拟。
    如果不是这种情况,它将在上下文中将模拟作为Bean添加。

    Javadoc参考:

    Annotation that can be used to add mocks to a Spring
    ApplicationContext.

    ...

    If any existing single bean of the same type defined in the context
    will be replaced by the mock, if no existing bean is defined a new one
    will be added.

    什么时候使用经典/普通Mockito以及何时从Spring Boot使用@MockBean

    单元测试旨在与其他组件隔离地测试组件,并且单元测试也有一个要求:执行时间要尽可能快,因为这些测试每天可能在开发人员计算机上执行数十次。

    因此,这是一个简单的准则:

    当您编写不需要从Spring Boot容器中获取任何依赖项的测试时,遵循经典/普通Mockito的方法是:它快速且有利于隔离测试的组件。
    如果您的测试需要依赖于Spring Boot容器,并且您还想添加或模拟其中一个容器bean,则可以使用Spring Boot中的@MockBean

    Spring Boot @MockBean的典型用法

    当我们编写一个用@WebMvcTest注释的测试类(Web测试切片)时。

    Spring Boot文档很好地总结了这一点:

    Often @WebMvcTest will be limited to a single controller and used in
    combination with @MockBean to provide mock implementations for
    required collaborators.

    这是一个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.Mockito;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
    import org.springframework.boot.test.mock.mockito.MockBean;
    import org.springframework.http.MediaType;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.servlet.MockMvc;

    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

    @RunWith(SpringRunner.class)
    @WebMvcTest(FooController.class)
    public class FooControllerTest {

        @Autowired
        private MockMvc mvc;

        @MockBean
        private FooService fooServiceMock;

        @Test
        public void testExample() throws Exception {
             Foo mockedFoo = new Foo("one","two");

             Mockito.when(fooServiceMock.get(1))
                    .thenReturn(mockedFoo);

             mvc.perform(get("foos/1")
                .accept(MediaType.TEXT_PLAIN))
                .andExpect(status().isOk())
                .andExpect(content().string("one two"));
        }

    }


    最后,它很容易解释。如果仅查看注释的javadocs,您将看到不同之处:

    @模拟:(org.mockito.Mock)

    Mark a field as a mock.

    • Allows shorthand mock creation.
    • Minimizes repetitive mock creation code.
    • Makes the test class more readable.
    • Makes the verification error easier to read because the field name is used to identify the mock.

    @MockBean:(org.springframework.boot.test.mock.mockito.MockBean)

    Annotation that can be used to add mocks to a Spring ApplicationContext. Can be used as a class level annotation or on fields in either @Configuration classes, or test classes that are @RunWith the SpringRunner.

    Mocks can be registered by type or by bean name. Any existing single bean of the same type defined in the context will be replaced by the mock, if no existing bean is defined a new one will be added.

    When @MockBean is used on a field, as well as being registered in the application context, the mock will also be injected into the field.

    Mockito.mock()

    Its just the representation of a @Mock.


    我可以看到的1个区别是@Mock使模拟对象具有该类类型的默认值,其中默认情况下使用@MockBean创建的模拟对象被分配了Null值。为了在测试类中显式地使用它,我们需要再次实例化它。