Mock

摘要:
MockServer主要适用于接口和性能测试,构造一个假的服务返回预期的结果,进行测试。

一、Mock

1.1 什么是 Mock

mock 是在测试过程中,对于一些不容易构造/获取的对象,创建一个 mock 对象来模拟对象的行为。

1.2 什么时候使用

* 单元测试时,使用外部资源或第三方库代码
* 并行开发时,另一方还没有开发完毕    

1.3 Mock 分类

  • Mock 对象
主要适用于单元测试,写入一些预期的值,通过它进行自己想要的测试。
  • Mock Server
主要适用于接口和性能测试,构造一个假的服务返回预期的结果,进行测试。

1.4 技术选型

Java 阵营 中主要的 Mock 测试工具有 **Mockito ,JMock,MockCreator,Mockrunner,EasyMock,MockMaker,PowerMock ** 等

我们这里重点讲解 **Mockito 和 PowerMock ** 。

二、Mockito 实践

2.1 引入依赖

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.10.19</version>
    <scope>test</scope>
</dependency>

2.2 验证行为

@Test
public void testList(){
    // 创建模拟对象
    List<String> mockList = mock(List.class);

    // 模拟对象执行操作
    mockList.add("one");
    mockList.clear();

    // 验证
    verify(mockList).add("one");
    verify(mockList).clear();
}

执行程序,发现测试通过,证明 Mockito 可以验证行为。

2.3 验证行为调用次数

@Test
public void testListBehaviorExecutionFrequency() {
    // 创建模拟对象
    List<String> mockList = mock(List.class);

    // 模拟对象执行操作
    mockList.add("1");
    mockList.add("2");
    mockList.add("2");
    mockList.add("3");
    mockList.add("3");
    mockList.add("3");
    mockList.add("4");
    mockList.add("4");
    mockList.add("4");
    mockList.add("4");
    mockList.clear();

    // 验证
    verify(mockList).add("1");
    // 验证执行次数
    verify(mockList, times(1)).add("1");
    verify(mockList, times(2)).add("2");
    verify(mockList, times(3)).add("3");
    verify(mockList, times(4)).add("4");
    verify(mockList, times(1)).clear();

    // 验证从来没有执行的方法
    verify(mockList, never()).add("0");

    // 至少执行过一次
    verify(mockList, atLeastOnce()).add("4");
    // 最小执行过2次
    verify(mockList, atLeast(2)).add("4");
    // 最多执行过5次
    verify(mockList, atMost(5)).add("4");
}

2.4 验证行为执行的顺序

@Test
public void testListBehaviorExecutionOrderBySingle(){
    // 创建模拟对象
    List<String> mockList = mock(List.class);

    // 模拟对象执行操作
    mockList.add("1");
    mockList.add("2");
    mockList.add("3");

    InOrder inOrder = inOrder(mockList);
    // 验证先执行add 1 ,再执行添加 3,可以发现跳过了添加 2 的行为,说明可以只关注感兴趣的交互即可
    inOrder.verify(mockList).add("1");
    inOrder.verify(mockList).add("3");
}
@Test
public void testListBehaviorExecutionOrderByMultiple() {
    // 创建模拟对象
    List<String> firsMockList = mock(List.class);
    List<String> secondMockList = mock(List.class);

    // 模拟对象执行操作
    firsMockList.add("firsMockList add ");
    secondMockList.add("secondMockList add ");

    InOrder inOrder = inOrder(firsMockList,secondMockList);
     // 验证执行顺序
    inOrder.verify(firsMockList).add("firsMockList add ");
    inOrder.verify(secondMockList).add("secondMockList add ");
}

2.5 验证从未调用过的对象

@Test
public void testNoOperating() {
    List<String> notOperatingList = mock(List.class);
    verifyNoInteractions(notOperatingList);
}

2.6 查找冗余调用

@Test
public void testNoMoreInteractions(){
    List<String> mockList = mock(List.class);

    mockList.add("one");
    mockList.add("two");

    verify(mockList).add("one");

    //将抛出异常,因为 `mockList.add("two");` 是额外的调用
    verifyNoMoreInteractions(mockList);
}

2.7 模拟存根

@Test
public void testStubbing(){
    // 创建模拟对象
    List mockList = mock(List.class);

    // 启用存根方法,当什么时候执行什么操作
    when(mockList.get(0)).thenReturn("1");
    when(mockList.get(3)).thenReturn("3");

    Assert.assertEquals("1",mockList.get(0));
    Assert.assertEquals("3",mockList.get(3));
    Assert.assertEquals(null,mockList.get(99));
}

说明:

* 默认情况下,对于所有返回值的方法,模拟将酌情返回null,原始/原始包装器值或空集合。例如,对于int / Integer为0,对于boolean / Boolean为false。
* 存根可以被覆盖:例如,通用存根可以进入夹具设置,但是测试方法可以覆盖它。请注意,过多的存根是潜在的代码异味,表明存在过多的存根
* 一旦存根,该方法将始终返回存根值,而不管其被调用了多少次。
* 最后一次存根更为重要-当您多次对具有相同参数的相同方法进行存根时。换句话说:存根的顺序很重要,但很少有意义,例如,存根完全相同的方法调用时或有时使用参数匹配器时,等等。

2.8 模拟异常抛出

@Test
public void testThrowException(){
    // 创建模拟对象
    List mockList = mock(List.class);
    // 指定什么操作将抛出异常
    doThrow(new RuntimeException()).when(mockList).clear();
    // 该方法将抛出异常
    mockList.clear();
}

2.9 模拟创建的简写- @Mock注释

@RunWith(MockitoJUnitRunner.class)
public class MockTest{

    @Mock
    private List list;
    @Test
    public void testMockAnnotation(){
        list.add("one");
        verify(list).add("one");
    }
}   

需要配合 @RunWith(MockitoJUnitRunner.class) 注解使用。

2.10 参数匹配器

实现类:

@Service
public class UserServiceImpl implements UserService {

    private final SysUserMapper sysUserMapper;

    public UserServiceImpl(SysUserMapper sysUserMapper) {
        this.sysUserMapper = sysUserMapper;
    }

    @Override
    public int count(String account) {
        SysUserExample example = new SysUserExample();
        example.createCriteria().andAccountEqualTo(account);
        List<SysUser> users = sysUserMapper.selectByExample(example);
        return users.size();
    }

}

测试类:

public class UserServiceTest {
    private UserService userService;
    private SysUserMapper sysUserMapper;

    @Before
    public void setUp() {
        sysUserMapper = mock(SysUserMapper.class);
        userService = new UserServiceImpl(sysUserMapper);
    }
    
    @Test
    public void testMock() {
        // 准备数据
        String account1 = "admin";       
        List<SysUser> userList = new ArrayList<>();
        userList.add(getOneUser(account1));
        // 模拟行为
        when(sysUserMapper.selectByExample(any(SysUserExample.class)))
                .thenReturn(userList);
        // 执行方法
        int result = userService.count(account1);
        // 验证结果
        assertThat(result, is(1));
    }
}    

其他类型参数:

anyInt();
anyString();
anyX();

更多使用方法请查看 文档

三、PowerMock 实践

PowerMock 主要用于静态和私有方法的模拟。

3.1 引入依赖

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>

3.2 使用说明

相关注解:所有测试类均须加上以下注解

// 表明用 PowerMockerRunner来运行测试用例,否则无法使用PowerMock
@RunWith(PowerMockRunner.class)
// 所有需要测试的类,列在此处,以逗号分隔
@PrepareForTest({UserController.class, FileHelper.class})

3.3 模拟静态方法调用

public class PrintUtils {

    public static String getPirntMessage() {
        return "123";
    }
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(PrintUtils.class)
public class PrintUtilsTest {


    @Test
    public void shouldReturnExpectedString() {
        String expectedString = "mockString";
        
        PowerMockito.mockStatic(PrintUtils.class);
        PowerMockito.when(PrintUtils.getPirntMessage()).thenReturn(expectedString);

        String result =  PrintUtils.getPirntMessage();
        assertThat(result,is(expectedString));
    }

}

更多使用方法请查看 文档

免责声明:文章转载自《Mock》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇初探机器学习之使用讯飞TTS服务实现在线语音合成java 多线程--------(一)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Dapper解析嵌套的多层实体类

在作项目的时候,我会将一些不涉及查询的字段,形成JSON统一存放在一个字段中,向下面这样的来建实体类, public class WechatModel { public string wechatid { get; set; } public WxMpModel wxmpinfo { get; set; } } p...

EasyPoi 导入导出Excel时使用GroupName的踩坑解决过程

一、开发功能介绍: 简单的一个excel导入功能 二、Excel导入模板(大致模板没写全): 姓名 性别 生日 客户分类 联系人姓名 联系人部门  备注 材料 综合 采购 张三 男 1994/05/25 1 1 1 张三 开发部   李四 男 1994/05/25 1 1 1 张三 开发部   王五 男 1994/05/25 1 1 1...

MySQL入门笔记(二)

MySQL的数据类型、数据库操作、针对单表的操作以及简单的记录操作可参考:MySQL入门笔记(一) 五、子查询   子查询可简单地理解为查询中的查询,即子查询外部必然还有一层查询,并且这里的查询并非仅仅指SELECT的查询操作,而是包括INSERT、DELETE、SET等操作在内的所有操作。 1. 使用比较运算符的子查询 operand comparis...

Java消息系统简单设计与实现

前言:由于导师在我的毕设项目里加了消息系统(本来想水水就过的..),没办法...来稍微研究研究吧..简单简单... 需求分析 我的毕设是一个博客系统,类似于简书这样的,所以消息系统也类似,在用户的消息里包含了有:喜欢和赞、评论、关注、私信这样的一类东西,这样的一个系统应该包含以下的功能: 当用户评论/关注/点赞时能够通知到被评论/关注/点赞的用户,并...

Java 字符串常用操作(String类)

字符串查找 String提供了两种查找字符串的方法,即indexOf与lastIndexOf方法。 1、indexOf(String s) 该方法用于返回参数字符串s在指定字符串中首次出现的索引位置,当调用字符串的indexOf()方法时,会从当前字符串的开始位置搜索s的位置;如果没有检索到字符串s,该方法返回-1 1 String str ="We a...

Java 反射原理

一、Java 反射的定义 反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法或者属性; 二、反射提供的功能: 在运行时判断任意一个对象所属的类; 在运行时构造任意一个类的对象; 在运行时判断任意一个类所具有的成员变量和方法; 在运行时调用任意一个对象的方法; 生成...