在创建测试和模拟依赖关系时,这三种方法之间有什么区别?

@MockBean: @MockBean 我的服务我的服务; @Mock: @Mock 我的服务我的服务; Mockito.mock() MyService myservice = Mockito.mock(MyService.class);


最后很容易解释。如果你只看注释的javadocs,你会发现区别:

@Mock:(org.mockito.Mock)

将一个字段标记为mock。

允许简化模拟创建。 最小化重复的模拟创建代码。 使测试类更具可读性。 使验证错误更容易阅读,因为字段名用于标识模拟。

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

可用于向Spring ApplicationContext添加模拟的注释。可以用作类级注释,也可以用于@Configuration类或@RunWith springgrunner的测试类中的字段。

mock可以按类型或bean名注册。任何在上下文中定义的相同类型的现有单个bean都将被mock替换,如果没有定义现有bean,则将添加一个新的bean。

当在字段上使用@MockBean并在应用程序上下文中注册时,mock也将被注入到字段中。

Mockito.mock()

它只是一个@Mock的表示。


普通Mockito库

import org.mockito.Mock;
...
@Mock
MyService myservice;

and

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

它们来自Mockito库,并且在功能上是等价的。 它们允许模拟类或接口,并记录和验证其中的行为。

使用注释的方式更短,因此更可取,也经常是首选。


注意,要在测试执行期间启用Mockito注释,可以使用 必须调用mokitoannotations . initmocks(此)静态方法。 为避免测试之间的副作用,建议在每次测试执行之前执行:

@Before 
public void initMocks() {
    MockitoAnnotations.initMocks(this);
}

另一种启用Mockito注释的方法是通过指定执行此任务的MockitoJUnitRunner和其他有用的事情来使用@RunWith注释测试类:

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

Spring Boot库包装Mockito库

这确实是一个Spring Boot类:

import org.springframework.boot.test.mock.mockito.MockBean;
...
@MockBean
MyService myservice;

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

它允许在Spring ApplicationContext中添加Mockito mock。 如果上下文中存在与声明的类兼容的bean,则用mock替换它。 如果不是这样,它将mock作为bean添加到上下文中。

Javadoc参考:

可用于向Spring添加模拟的注释 ApplicationContext。 ... 上下文中定义的任何相同类型的现有单个bean 将被mock取代,如果没有现有的bean被定义为一个新的 将被添加。


什么时候使用经典/普通Mockito,什么时候从Spring Boot使用@MockBean ?

单元测试的设计目的是在组件与其他组件隔离的情况下测试组件,单元测试也有一个要求:在执行时间方面尽可能快,因为这些测试可能每天在开发人员机器上执行十几次。

因此,这里有一个简单的指导方针:

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


Spring Boot @MockBean的典型用法

当我们编写带有@WebMvcTest (web测试片)注释的测试类时。

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

通常@WebMvcTest将被限制在单个控制器中,并用于 结合@MockBean来提供的模拟实现 必需的合作者。

这里有一个例子:

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"));
    }

}

Mocktio.mock() :-

将创建类或接口的模拟对象。我们可以用 此模拟用于存根返回值并验证它们是否被调用。 对于模拟对象,必须使用when(..)和thenReturn(..)方法 其类方法将在测试用例执行期间被调用。

@Mock: -

这是mock()方法的简写,因此更可取,而且经常使用 使用。 mock()和@Mock在功能上是等价的。 当字段名称出现在错误消息中时,更容易在模拟失败中识别问题。

为了在测试执行期间启用Mockito注释,我们需要调用MockitoAnnotations.initMocks(this)方法,但是这个方法已弃用,我们可以调用- MockitoAnnotations.openMocks(this)。为了避免副作用,建议在测试用例执行之前调用此方法。

启用Mockito注释的另一种方法是通过指定执行此任务的MockitoJUnitRunner和其他有用的事情,用@RunWith注释测试类。

@MockBean: - 它用于将模拟对象添加到spring应用程序上下文中。 这个模拟将替换应用程序中相同类型的现有bean 上下文。如果没有可用的bean,那么将添加新的bean。这 在集成测试用例中很有用。

当我们编写一个不需要任何来自Spring Boot容器的依赖项的测试用例时,使用经典/普通Mockito,它速度快,有利于被测试组件的隔离。

如果我们的测试用例需要依赖Spring Boot容器,并希望添加或模拟其中一个容器bean,则使用@MockBean。