Java-Mock简化单元测试

373814.jpg

单元测试目的

维基百科对单元测试的定义:

单元测试(英语:Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。

单元测试的目标是隔离程序部件并证明这些单个部件是正确的。
  • 画外音:单元测试是比较细粒度的测试,是对接口、方法、函数的测试,目的是保障代码按照正确的方式去执行,提高代码质量。

单元测试实施原则

Mock脱离数据库 + 不启动Spring + 优化测试速度 + 不引入项目组件

单元测试不应该依赖数据,依赖外部服务或组件等,会对其他数据产生影响的情况。启动Spring容器,一般比较慢,可能会启动消息监听消费消息,定时任务的执行等,对数据产生影响。

Mock测试就是在测试过程中,对那些当前测试不关心的,不容易构建的对象,用一个虚拟对象来代替测试的情形。

说白了:就是解耦(虚拟化)要测试的目标方法中调用的其它方法,例如:Service的方法调用Mapper类的方法,这时候就要把Mapper类Mock掉(产生一个虚拟对象),这样我们可以自由的控制这个Mapper类中的方法,让它们返回想要的结果、抛出指定异常、验证方法的调用次数等等。

减少单元测试对外部的依赖和副作用,提高单元测试效率

  1. 不使用 @Autowired,@Resource, 需要启动 Spring 容器,测试速度慢,会产生副作用;
  2. 不使用 @SpringBootTest,@SpringBootTest(classes = Application.class), 这会启动整个 SpringBoot 服务
  3. 不应调用数据库,除非是做数据库操作相关的测试,虽然可配置事务回滚,但大多数情况下还是会产生脏数据等问题
  4. 使用Assert断言,用于判断某个特定条件下某个方法的行为,为了证明某段代码的执行结果和期望的一致
  • 画外音:单元测试应小而轻,提交测试效率,较少对外部的依赖,比如数据库、Spring容器、网络服务等,而只关心我们自己的代码,通过Mock来解决对外部的依赖

Mockito的使用

基本使用

  1. 使用静态方法 mock()
  2. 使用注解 @Mock 标注

如果使用@Mock注解, 必须去触发所标注对象的创建. 可以使用 MockitoRule来实现. 它调用了静态方法MockitoAnnotations.initMocks(this) 去初始化这个被注解标注的字段.或者也可以使用@RunWith(MockitoJUnitRunner.class).

“when thenReturn”和”when thenThrow”
模拟对象可以根据传入方法中的参数来返回不同的值, when(….).thenReturn(….)方法是用来根据特定的参数来返回特定的值.

我们也可以使用像 anyString 或者 anyInt anyLong any 这样的方法来定义某个依赖数据类型的方法返回特定的值.

“doReturn when” 和 “doThrow when”
doReturn(…).when(…)的方法调用和when(….).thenReturn(….)类似.对于调用过程中抛出的异常非常有用.而doThrow则也是它的一个变体.

常用注解

@Mock:对函数的调用均执行mock(即虚假函数),不执行真正部分。

@Spy:对函数的调用均执行真正部分。

@InjectMocks:创建一个实例,简单的说是这个Mock可以调用真实代码的方法,使用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。

Mockito中的Mock和Spy都可用于拦截那些尚未实现或不期望被真实调用的对象和方法,并为其设置自定义行为。二者的区别在于Mock不真实调用,Spy会真实调用。

@MockBean: 功能同 @Mock, 只是会将实例放入 Spring 容器管理

@SpyBean: 功能同 @Spy, 只是会将实例放入 Spring 容器管理

  1. Spy 和 Mock 生成的对象不受 Spring 管理
  2. Spy 调用真实方法时,其它 bean 是无法注入的,要使用注入,要使用 SpyBean
  3. SpyBean 和 MockBean 生成的对象受 Spring 管理,相当于自动替换对应类型 bean 的注入,比如 @Autowired、@Resource 等注入

最佳实践

// 不使用 @SpringBootTest(classes = Application.class)
@RunWith(SpringRunner.class)
public class ExamAnswerComponentTest {

    // 创建一个实例,会注入Mock变量
    @InjectMocks
    private ExamAnswerComponent examAnswerComponent = new ExamAnswerComponentImpl();

    // 相关操作会被Mock掉
    @Mock
    private ExamAnswerCacheObjectiveDAO examAnswerCacheObjectiveDAO;

    @Before
    public void setUp() {
        // 初始化Mock
        MockitoAnnotations.initMocks(this);

        // given...willReturn 指定方法参数,模拟返回值
        given(examAnswerCacheObjectiveDAO.selectByBizIdAndPaperAndQuestion(any(), any(), any()))
                .willReturn(new ExamAnswerCacheObjectivePO());
        given(examAnswerCacheObjectiveDAO.insert(any())).willReturn(1);
        given(examAnswerCacheObjectiveDAO.updateUserAnswerById(any(), any())).willReturn(1);
    }


    @Test
    public void saveOrUpdateAnswerCacheObjective() {

        ExamAnswerCacheObjectivePO po = new ExamAnswerCacheObjectivePO();
        po.setBizId(100000015L);
        po.setBizType(9);
        po.setUserAnswer("A");
        po.setGroupPaperId(1000320L);
        po.setQuestionId(1000042L);
        po.setQuestionType(1);

        int affect = examAnswerComponent.saveOrUpdateAnswerCacheObjective(po);
        System.out.println("affect = " + affect);
        Assert.assertTrue(affect > 0);
    }

}

参考

https://www.codenong.com/cs106503150/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容