在创建测试和模拟依赖关系时,这三种方法有什么区别?
@MockBean:
@MockBean MyService myservice;
@Mock:
@Mock MyService myservice;
Mockito.mock()
MyService myservice = Mockito.mock(MyService.class);
在创建测试和模拟依赖关系时,这三种方法有什么区别?
@MockBean:
@MockBean
MyService myservice;
@Mock:
@Mock
MyService myservice;
Mockito.mock()
MyService myservice = Mockito.mock(MyService.class);
Mockito库
import org.mockito.Mock;
...
@Mock
MyService myservice;
和
import org.mockito.Mockito;
...
MyService myservice = Mockito.mock(MyService.class);
这些代码片段来自Mockito库,具有相同的功能。
它们允许对类或接口进行模拟,并记录和验证其行为。
使用注释的方式更短,更可取,通常更受青睐。
请注意,在测试执行期间启用Mockito注释,需要调用MockitoAnnotations.initMocks(this)
静态方法。
为避免测试之间产生副作用,建议在每次测试执行之前执行此操作:
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
通过在测试类上注释@RunWith
并指定执行此任务和其他有用的事情的MockitoJUnitRunner
,可以启用Mockito注释的另一种方法:
另一种启用Mockito注释的方法是通过在测试类上使用@RunWith
注释并指定MockitoJUnitRunner
来执行此任务以及其他有用的操作:
@RunWith(org.mockito.runners.MockitoJUnitRunner.class)
public MyClassTest{...}
封装Mockito库的Spring Boot库
这确实是一个Spring Boot类:
import org.springframework.boot.test.mock.mockito.MockBean;
...
@MockBean
MyService myservice;
该类包含在spring-boot-test
库中。
它允许将Mockito模拟对象添加到Spring ApplicationContext
中。
如果上下文中存在与声明类兼容的bean,则会将其替换为mock;
如果不存在,则会将mock作为bean添加到上下文中。
Javadoc参考:
注释可用于向Spring ApplicationContext添加模拟对象。
...
如果已在上下文中定义了与类型相同的任何现有单个bean,则将其替换为mock,如果没有定义现有bean,则将添加一个新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"));
}
}
最后来解释一下,很容易理解。如果你查看注解的javadocs,你会看到以下区别:
@Mock: (org.mockito.Mock
)
将一个字段标记为mock。
- 允许简写的mock创建方式。
- 最小化重复的mock创建代码。
- 使测试类更易读。
- 使验证错误更易于阅读,因为字段名用于标识mock。
@MockBean: (org.springframework.boot.test.mock.mockito.MockBean
)
可以用作类级别的注解,也可以在
@Configuration
类或@RunWith
SpringRunner的测试类中的字段上使用,用于向Spring ApplicationContext添加mocks。
mocks可以按类型或bean名称注册。如果上下文中定义了相同类型的现有单个bean,则该bean将被mock替换,如果未定义现有bean,则会添加新的bean。
当
@MockBean
用于字段时,除了在应用程序上下文中注册之外,mock还将注入到字段中。
Mockito.mock()
这只是
@Mock
的表示形式。
@MockBean
和 @Mock
的唯一区别是前者会将模拟对象注入到 Spring 应用上下文中,而后者不会吗? - Doug@MockBean
,您需要使用@RunWith(SpringRunner.class)
注释该类。但是,如果想要使用@Mock
,可以使用@RunWith(MockitoJUnitRunner.class)
并调用initMocks()
,正如@Florian-schaetz所提到的那样。 @Mock
也可以与SpringRunner一起使用,但需要额外加载applicationContext,从而增加了开销。 - Jaison VargheseMocktio.mock() :-
when(..)
和thenReturn(..)
方法。@Mock
:-
mock()
方法的简写,因此它更可取且经常被使用。mock()
和@Mock
在功能上是等效的。为了在测试执行期间启用Mockito注释,我们需要调用MockitoAnnotations.openMocks(this)
方法,而不是已弃用的MockitoAnnotations.initMocks(this)
方法。为避免副作用,建议在测试用例执行之前调用此方法。
另一种启用Mockito注释的方式是通过使用@RunWith
注释测试类,并指定执行此任务以及其他有用任务的MockitoJUnitRunner。
@MockBean
:
它用于将Mock对象添加到Spring应用程序上下文中。该Mock对象将替换应用程序上下文中相同类型的现有bean。如果没有可用的bean,则将添加新bean。这对于集成测试用例非常有用。
当我们编写不需要从Spring Boot容器中获取任何依赖项的测试用例时,使用经典/普通的Mockito,它快速且支持被测试组件的隔离。
如果我们的测试用例需要依赖于Spring Boot容器,并且想要添加或Mock容器中的一个Bean,则使用@MockBean
。
@MockBean
注解的作用是:该模拟将替代应用程序上下文中的任何现有相同类型的bean,如果没有定义相同类型的bean,则会包含一个新的。在集成测试
期间,当需要模拟特定的bean(如外部服务
)时,此注解非常有价值。
@MockBean
将替换应用程序上下文中声明相同类型的bean。如果您的Spring配置中已经定义了该类型的bean,则将替换它。注入是在声明@MockBean
的类中执行的。DI机制的工作方式是:您在DI上下文中注册一个对象,然后您可以在特定类中注入在Spring上下文中引用的对象。您不会在DI上下文中注入对象。 - davidxxx@MockBean
的问题在于它无法与Mockito.verify
一起使用。 - ACV