爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      一文让你快速上手 Mockito 单元测试框架

      首页 知识中心 云端实践 文章详情页

      一文让你快速上手 Mockito 单元测试框架

      2023-02-13 07:38:09 阅读次数:483

      the public

      前言

      在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

      生成 Mock 对象方式

      要使用 Mockito,首先需要在我们的项目中引入 Mockito 测试框架依赖,基于 Maven 构建的项目引入如下依赖即可:

      <dependency> 
        <groupId>org.mockito</groupId>  
        <artifactId>mockito-core</artifactId>  
        <version>3.3.3</version>  
        <scope>test</scope>
      </dependency>

      如果是基于 Gradle 构建的项目,则引入如下依赖:

      testCompile group: 'org.mockito', name: 'mockito-core', version: '3.3.3'

      使用 Mockito 通常有两种常见的方式来创建 Mock 对象。

      1、使用 Mockito.mock(clazz) 方式

      通过 Mockito 类的静态方法 mock 来创建 Mock 对象,例如以下创建了一个 List 类型的 Mock 对象:

      List<String> mockList = Mockito.mock(ArrayList.class);

      由于 mock 方法是一个静态方法,所以通常会写成静态导入方法的方式,即 List<String> mockList = mock(ArrayList.class)。

      2、使用 @Mock 注解方式

      第二种方式就是使用 @Mock 注解方式来创建 Mock 对象,使用该方式创需要注意的是要在运行测试方法前使用 MockitoAnnotations.initMocks(this) 或者单元测试类上加上 @ExtendWith(MockitoExtension.class) 注解,如下所示代码创建了一个 List 类型的 Mock 对象(PS: @BeforeEach 是 Junit 5 的注解,功能类似于 Junit 4 的 @Before 注解。):

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */
      
      @ExtendWith(MockitoExtension.class)
      public class MockitoTest {
          @Mock
          private List<String> mockList;
      
          @BeforeEach
          public void beforeEach() {
              MockitoAnnotations.initMocks(this);
          }
      }

      验证性测试

      Mockito 测试框架中提供了 Mockito.verify 静态方法让我们可以方便的进行验证性测试,比如方法调用验证、方法调用次数验证、方法调用顺序验证等,下面看看具体的代码。

      验证方法单次调用

      验证方法单次调用的话直接 verify 方法后加上待验证调用方法即可,以下代码的功能就是验证 mockList 对象的 size 方法被调用一次。

      /** * @author mghio * @date: 2020-05-28 * @version: 1.0 * @description: * @since JDK 1.8 */ 
      @ExtendWith(MockitoExtension.class)
      public class MockitoVerifyTest {
          @Mock
          List<String> mockList;
      
          @Test
          void verify_SimpleInvocationOnMock() {
              mockList.size();
              verify(mockList).size();
          }
      }
      验证方法调用指定次数

      除了验证单次调用,我们有时候还需要验证一些方法被调用多次或者指定的次数,那么此时就可以使用 verify + times 方法来验证方法调用指定次数,同时还可以结合 atLeast + atMost 方法来提供调用次数范围,同时还有 never 等方法验证不被调用等。

      /** * @author mghio * @date: 2020-05-28 * @version: 1.0 * @description: * @since JDK 1.8 */@ExtendWith(MockitoExtension.class)public class MockitoVerifyTest {  @Mock  List<String> mockList;  @Test  void verify_NumberOfInteractionsWithMock() {    mockList.size();    mockList.size();    verify(mockList, times(2)).size();    verify(mockList, atLeast(1)).size();    verify(mockList, atMost(10)).size();  }}
      验证方法调用顺序

      同时还可以使用 inOrder 方法来验证方法的调用顺序,下面示例验证 mockList 对象的 size、add 和 clear 方法的调用顺序。

      /** * @author mghio * @date: 2020-05-28 * @version: 1.0 * @description: * @since JDK 1.8 */ 
      @ExtendWith(MockitoExtension.class)
      public class MockitoVerifyTest {
          @Mock
          List<String> mockList;
      
          @Test
          void verify_OrderedInvocationsOnMock() {
              mockList.size();
              mockList.add("add a parameter");
              mockList.clear();
      
              InOrder inOrder = inOrder(mockList);
              inOrder.verify(mockList).size();
              inOrder.verify(mockList).add("add a parameter");
              inOrder.verify(mockList).clear();
          }
      }

      以上只是列举了一些简单的验证性测试,还有验证测试方法调用超时以及更多的验证测试可以通过相关官方文档探索学习。

      验证方法异常

      异常测试我们需要使用 Mockito 框架提供的一些调用行为定义,Mockito 提供了 when(...).thenXXX(...) 来让我们定义方法调用行为,以下代码定义了当调用 mockMap 的 get 方法无论传入任何参数都会抛出一个空指针 NullPointerException 异常,然后通过 Assertions.assertThrows 来验证调用结果。

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */
      @ExtendWith(MockitoExtension.class)
      public class MockitoExceptionTest {  
      @Mock  
      public Map<String, Integer> mockMap;  
      @Test  
      public void whenConfigNonVoidReturnMethodToThrowEx_thenExIsThrown() {    
       when(mockMap.get(anyString())).thenThrow(NullPointerException.class);   
        assertThrows(NullPointerException.class, () ->    mockMap.get("mghio")); 
       }
      }

      同时 when(...).thenXXX(...) 不仅可以定义方法调用抛出异常,还可以定义调用方法后的返回结果,比如 when(mockMap.get("mghio")).thenReturn(21); 定义了当我们调用 mockMap 的 get 方法并传入参数 mghio 时的返回结果是 21。这里有一点需要注意,使用以上这种方式定义的 mock 对象测试实际并不会影响到对象的内部状态,如下图所示:

      mockito_mock_object_thennoaffect.png

      虽然我们已经在 mockList 对象上调用了 add 方法,但是实际上 mockList 集合中并没有加入 mghio,这时候如果需要对 mock 对象有影响,那么需要使用 spy 方式来生成 mock 对象。

      public class MockitoTest {
          private List<String> mockList = spy(ArrayList.class);
      
          @Test
          public void add_spyMockList_thenAffect() {
              mockList.add("mghio");
              assertEquals(0, mockList.size());
          }
      }

      断点后可以发现当使用 spy 方法创建出来的 mock 对象调用 add 方法后,mghio 被成功的加入到 mockList 集合当中。

      mockito_mock_object_thenhasaffect.png

      与 Spring 框架集成

      Mockito 框架提供了 @MockBean 注解用来将 mock 对象注入到 Spring 容器中,该对象会替换容器中任何现有的相同类型的 bean,该注解在需要模拟特定bean(例如外部服务)的测试场景中很有用。如果使用的是 Spring Boot 2.0+ 并且当前容器中已有相同类型的 bean 的时候,需要设置 spring.main.allow-bean-definition-overriding 为 true(默认为 false)允许 bean 定义覆盖。下面假设要测试通过用户编码查询用户的信息,有一个数据库操作层的 UserRepository,也就是我们等下要 mock 的对象,定义如下:

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */@Repositorypublic interface UserRepository {  User findUserById(Long id);}

      还有用户操作的相关服务 UserService 类,其定义如下所示:

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */@Servicepublic class UserService {  private UserRepository userRepository;  public UserService(UserRepository userRepository) {    this.userRepository = userRepository;  }  public User findUserById(Long id) {    return userRepository.findUserById(id);  }}

      在测试类中使用 @MockBean 来标注 UserRepository 属性表示这个类型的 bean 使用的是 mock 对象,使用 @Autowired 标注表示 UserService 属性使用的是 Spring 容器中的对象,然后使用 @SpringBootTest 启用 Spring 环境即可。

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */@SpringBootTestpublic class UserServiceUnitTest {  @Autowired  private UserService userService;  @MockBean  private UserRepository userRepository;  @Test  public void whenUserIdIsProvided_thenRetrievedNameIsCorrect() {    User expectedUser = new User(9527L, "mghio", "18288888880");    when(userRepository.findUserById(9527L)).thenReturn(expectedUser);    User actualUser = userService.findUserById(9527L);    assertEquals(expectedUser, actualUser);  }}

      Mockito 框架的工作原理

      通过以上介绍可以发现, Mockito 非常容易使用并且可以方便的验证一些方法的行为,相信你已经看出来了,使用的步骤是先创建一个需要 mock 的对象 Target ,该对象如下:

      public class Target {  public String foo(String name) {    return String.format("Hello, %s", name);  }}

      然后我们直接使用 Mockito.mock 方法和 when(...).thenReturn(...) 来生成 mock 对象并指定方法调用时的行为,代码如下:

      @Testpublic void test_foo() {  String expectedResult = "Mocked mghio";  when(mockTarget.foo("mghio")).thenReturn(expectedResult);  String actualResult = mockTarget.foo("mghio");  assertEquals(expectedResult, actualResult);}

      仔细观察以上 when(mockTarget.foo("mghio")).thenReturn(expectedResult) 这行代码,首次使用我也觉得很奇怪,when 方法的入参竟然是方法的返回值 mockTarget.foo("mghio"),觉得正确的代码应该是这样 when(mockTarget).foo("mghio"),但是这个写法实际上无法进行编译。既然 Target.foo 方法的返回值是 String 类型,那是不是可以使用如下方式呢?

      Mockito.when("Hello, I am mghio").thenReturn("Mocked mghio");

      结果是编译通过,但是在运行时报错:

      mockito_when_method_runtime_error.png

      从错误提示可以看出,when 方法需要一个方法调用的参数,实际上它只需要 more 对象方法调用在 when 方法之前就行,我们看看下面这个测试代码:

      @Testpublic void test_mockitoWhenMethod() {  String expectedResult = "Mocked mghio";  mockTarget.foo("mghio");  when("Hello, I am mghio").thenReturn(expectedResult);  String actualResult = mockTarget.foo("mghio");  assertEquals(expectedResult, actualResult);}

      以上代码可以正常测试通过,结果如下:

      mockito_mock_when_method_pass.png

      为什么这样就可以正常测试通过?是因为当我们调用 mock 对象的 foo 方法时,Mockito 会拦截方法的调用然后将方法调用的详细信息保存到 mock 对象的上下文中,当调用到 Mockito.when 方法时,实际上是从该上下文中获取最后一个注册的方法调用,然后把 thenReturn 的参数作为其返回值保存,然后当我们的再次调用 mock 对象的该方法时,之前已经记录的方法行为将被再次回放,该方法触发拦截器重新调用并且返回我们在 thenReturn 方法指定的返回值。以下是 Mockito.when 方法的源码:

      mockito_when_sourcecode.png

      该方法里面直接使用了 MockitoCore.when 方法,继续跟进,该方法源码如下:

      mockito_when_method_mockitocore_sourcecode.png

      仔细观察可以发现,在源码中并没有用到参数 methodCall,而是从 MockingProgress 实例中获取 OngoingStubbing 对象,这个 OngoingStubbing 对象就是前文所提到的上下文对象。个人感觉是 Mockito 为了提供简洁易用的 API 然后才制造了 when 方法调用的这种“幻象”,简而言之,Mockito 框架通过方法拦截在上下文中存储和检索方法调用详细信息来工作的。

      如何实现一个微型的 Mock 框架

      知道了 Mockito 的运行原理之后,接下来看看要如何自己去实现一个类似功能的 mock 框架出来,看到方法拦截这里我相信你已经知道了,其实这就是 AOP 啊,但是通过阅读其源码发现 Mockito 其实并没有使用我们熟悉的 Spring AOP 或者 AspectJ 做的方法拦截,而是通过运行时增强库 Byte Buddy 和反射工具库 Objenesis 生成和初始化 mock 对象的。
      现在,通过以上分析和源码阅读可以定义出一个简单版本的 mock 框架了,将自定义的 mock 框架命名为 imock。这里有一点需要注意的是,Mockito 有一个好处是,它不需要进行初始化,可以直接通过其提供的静态方法来立即使用它。在这里我们也使用相同名称的静态方法,通过 Mockito 源码:

      mockito_delegate_mockitocore.png

      很容易看出 Mockito 类最终都是委托给 MockitoCore 去实现的功能,而其只提供了一些面向使用者易用的静态方法,在这里我们也定义一个这样的代理对象 IMockCore,这个类中需要一个创建 mock 对象的方法 mock 和一个给方法设定返回值的 thenReturn 方法,同时该类中持有一个方法调用详情 InvocationDetail 集合列表,这个类是用来记录方法调用详细信息的,然后 when 方法仅返回列表中的最后一个 InvocationDetail,这里列表可以直接使用 Java 中常用的 ArrayList 即可,这里的 ArrayList 集合列表就实现了 Mockito 中的 OngoingStubbing 的功能。
      根据方法的三要素方法名、方法参数和方法返回值很容易就可以写出 InvocationDetail 类的代码,为了对方法在不同类有同名的情况区分,还需要加上类全称字段和重写该类的 equals 和 hashCode 方法(判断是否在调用方法集合列表时需要根据该方法判断),代码如下所示:

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */ public class InvocationDetail<T> {
          private String attachedClassName;
          private String methodName;
          private Object[] arguments;
          private T result;
      
          public InvocationDetail(String attachedClassName, String methodName,
              Object[] arguments) {
              this.attachedClassName = attachedClassName;
              this.methodName = methodName;
              this.arguments = arguments;
          }
      
          public void thenReturn(T t) {
              this.result = t;
          }
      
          public T getResult() {
              return result;
          }
      
          @Override
          public boolean equals(Object o) {
              if (this == o) {
                  return true;
              }
      
              if ((o == null) || (getClass() != o.getClass())) {
                  return false;
              }
      
              InvocationDetail<?> behaviour = (InvocationDetail<?>) o;
      
              return Objects.equals(attachedClassName, behaviour.attachedClassName) &&
              Objects.equals(methodName, behaviour.methodName) &&
              Arrays.equals(arguments, behaviour.arguments);
          }
      
          @Override
          public int hashCode() {
              int result = Objects.hash(attachedClassName, methodName);
              result = (31 * result) + Arrays.hashCode(arguments);
      
              return result;
          }
      }

      接下来就是如何去创建我们的 mock 对象了,在这里我们也使用 Byte Buddy 和 Objenesis 库来创建 mock 对象,IMockCreator 接口定义如下:

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */public interface IMockCreator {  <T> T createMock(Class<T> mockTargetClass, List<InvocationDetail> behaviorList);}

      实现类 ByteBuddyIMockCreator 使用 Byte Buddy 库在运行时动态生成 mock 类对象代码然后使用 Objenesis 去实例化该对象。代码如下:

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */ 
      public class ByteBuddyIMockCreator implements IMockCreator {
          private final ObjenesisStd objenesisStd = new ObjenesisStd();
      
          @Override
          public <T> T createMock(Class<T> mockTargetClass,
              List<InvocationDetail> behaviorList) {
              ByteBuddy byteBuddy = new ByteBuddy();
              Class<?extends T> classWithInterceptor = byteBuddy.subclass(mockTargetClass)
                                                                .method(ElementMatchers.any())
                                                                .intercept(MethodDelegation.to(
                          InterceptorDelegate.class))
                                                                .defineField("interceptor",
                      IMockInterceptor.class, Modifier.PRIVATE)
                                                                .implement(IMockIntercepable.class)
                                                                .intercept(FieldAccessor.ofBeanProperty())
                                                                .make()
                                                                .load(getClass()
                                                                          .getClassLoader(),
                      Default.WRAPPER).getLoaded();
              T mockTargetInstance = objenesisStd.newInstance(classWithInterceptor);
              ((IMockIntercepable) mockTargetInstance).setInterceptor(new IMockInterceptor(
                      behaviorList));
      
              return mockTargetInstance;
          }
      }

      基于以上分析我们可以很容易写出创建 mock 对象的 IMockCore 类的代码如下:

      public class IMockCore {
          private final List < InvocationDetail > invocationDetailList = new ArrayList < >(8);
          private final IMockCreator mockCreator = new ByteBuddyIMockCreator();
          public < T > T mock(Class < T > mockTargetClass) {
              T result = mockCreator.createMock(mockTargetClass, invocationDetailList);
              return result;
          }@SuppressWarnings("unchecked") public < T > InvocationDetail < T > when(T methodCall) {
              int currentSize = invocationDetailList.size();
              return (InvocationDetail < T > ) invocationDetailList.get(currentSize - 1);
          }
      }

      提供给使用者的类 IMock 只是对 IMockCore 进行的简单调用而已,代码如下:

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */
      public class IMock {
          private static final IMockCore IMOCK_CORE = new IMockCore();
          public static < T > T mock(Class < T > clazz) {
              return IMOCK_CORE.mock(clazz);
          }
          public static < T > InvocationDetail when(T methodCall) {
              return IMOCK_CORE.when(methodCall);
          }
      }

      通过以上步骤,我们就已经实现了一个微型的 mock 框架了,下面来个实际例子测试一下,首先创建一个 Target 对象:

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */
      public class Target {
          public String foo(String name) {
              return String.format("Hello, %s", name);
          }
      }

      然后编写其对应的测试类 IMockTest 类如下:

      /** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */
      public class IMockTest {@Test public void test_foo_method() {
              String exceptedResult = "Mocked mghio";
              Target mockTarget = IMock.mock(Target.class);
              IMock.when(mockTarget.foo("mghio")).thenReturn(exceptedResult);
              String actualResult = mockTarget.foo("mghio");
              assertEquals(exceptedResult, actualResult);
          }
      }

      以上测试的可以正常运行,达到了和 Mockito 测试框架一样的效果,运行结果如下:

      mockito_imock_test_pass.png

      上面只是列出了一些关键类的源码,自定义 IMock 框架的所有代码已上传至 Github 仓库 imock,感兴趣的朋友可以去看看。

      总结

      本文只是介绍了 Mockito 的一些使用方法,这只是该框架提供的最基础功能,更多高级的用法可以去官网阅读相关的文档,然后介绍了框架中 when(...).thenReturn(...) 定义行为方法的实现方式并按照其源码思路实现了一个相同功能的简易版的 imock 。虽然进行单元测试有很多优点,但是也不可盲目的进行单元测试,在大部分情况下只要做好对项目中逻辑比较复杂、不容易理解的核心业务模块以及项目中公共依赖的模块的单元测试就可以了。

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:http://ifeve.com/%e4%b8%80%e6%96%87%e8%ae%a9%e4%bd%a0%e5%bf%ab%e9%80%9f%e4%b8%8a%e6%89%8b-mockito-%e5%8d%95%e5%85%83%e6%b5%8b%e8%af%95%e6%a1%86%e6%9e%b6/,作者:并发编程网,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:SpringMVC执行流程

      下一篇:redis客户端连接(error) NOAUTH Authentication required

      相关文章

      2024-06-27 09:20:52

      谈谈架构和微服务

      不知从何时起,与同事,面试者,面试官谈起架构理念,总是绕不开微服务。甚至有时候听到这三个字的时候,脑壳会痛,相似的还有中台, 总觉得是旧瓶装新酒。 当然此时的盛行是有其原因的,猜测主要原因是容器化的盛行。

      2024-06-27 09:20:52
      String , the public
      2023-03-21 10:32:27

      Java中的状态模式实例教程

      状态模式是一种行为设计模式。适用于当对象的内在状态改变它自身的行为时。如果想基于对象的状态来改变自身的行为,通常利用对象的状态变量

      2023-03-21 10:32:27
      the public
      2023-03-21 10:32:27

      并发性能优化 &#8211; 降低锁粒度

      在高负载多线程应用中性能是非常重要的。为了达到更好的性能,开发者必须意识到并发的重要性。当我们需要使用并发时, 常常有一个

      2023-03-21 10:32:27
      java在线 , the public
      2023-03-21 10:32:27

      跟着实例学习ZooKeeper的用法: Curator框架应用

      前面的几篇文章介绍了一些ZooKeeper的应用方法, 本文将介绍Curator访问ZooKeeper的一些基本方法, 而不仅仅限于指定的Recipes, 你可以使用Curator API任意的访问ZooKeeper。CuratorFram

      2023-03-21 10:32:27
      the public
      2023-03-21 10:32:09

      Adopt Open JDK官方文档(五) Docker镜像

      5.1 复制镜像镜像可以从别的设备复制并导入本地的Docker仓库。保存镜像的命令为:或者保存镜像示例或者或者openjdk9-base-image.tar 和 openjdk9-base-image.tar.gz 的镜像已默认保

      2023-03-21 10:32:09
      java在线 , the public
      2023-03-21 10:31:48

      Java IO 之 InputStream源码

      一、InputStreamInputStream是一个抽象类,即表示所有字节输入流实现类的基类。它的作用就是抽象地表示所有从不同数据源产生输入的类,例如常见的FileInputStream、FilterInputStre

      2023-03-21 10:31:48
      the public
      2023-03-21 10:31:48

      Java构造器必知必会

      在面向对象编程中,编程人员应该在意“资源”。比如 在代码中,我们很在意在内存中String类型的hello,它是有一个生命周期的。在它生命周期中,初始化(initializ

      2023-03-21 10:31:48
      the public , 多线程同步
      2023-03-21 10:31:48

      《Java并发编程从入门到精通》显示锁Lock和ReentrantLock

      显示锁Lock和ReentrantLockLock是一个接口提供了无条件的、可轮询的、定时的、可中断的锁获取操作,所有加锁和解锁的方法都是显式的。包路径是:java.util.

      2023-03-21 10:31:48
      多线程同步 , the public
      2023-03-21 10:31:10

      Java注解全面解析

      1.基本语法注解定义看起来很像接口的定义。事实上,与其他任何接口一样,注解也将会编译成class文件。@Target(ElementType.Method)@Retention(RetentionPolicy.RUNTIME)public

      2023-03-21 10:31:10
      the public
      2023-03-16 08:48:22

      JVM优化之逃逸分析及锁消除

      逃逸分析——我们在上一篇文章中所介绍的由编译器完成的一项的分析技术——使得删除锁的优化成为了可能。如果它能确认某个加锁的对象不会逃逸出局部作用域,就可以进行锁删除。这意味着这个对象同时只可能被一个线程访问,因此也就没有必要防止其它线程对它进

      2023-03-16 08:48:22
      the public
      查看更多
      推荐标签

      作者介绍

      技术之路
      天翼云用户

      文章

      13

      阅读量

      5514

      查看更多

      最新文章

      跟着实例学习ZooKeeper的用法: Curator框架应用

      2023-03-21 10:32:27

      Spring框架提供的异步执行能力

      2023-02-13 09:25:28

      查看更多

      热门文章

      跟着实例学习ZooKeeper的用法: Curator框架应用

      2023-03-21 10:32:27

      Spring框架提供的异步执行能力

      2023-02-13 09:25:28

      查看更多

      热门标签

      客户端 实践 基础知识 Java 服务器 java 数据库 框架 python 服务端 学习 代码 简单 javascript 编程
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      Spring框架提供的异步执行能力

      跟着实例学习ZooKeeper的用法: Curator框架应用

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号