Mock方法时的参数匹配

  在mock方法时,对于方法的参数匹配是有要求的,只有要执行的方法的参数匹配mock方法里面的参数时,该mock方法才会起作用。Powermock提供了很多种参数匹配的方式,比如,如果需要精确地匹配参数,可以使用equal方式;如果需要灵活地匹配参数,可以使用any方式。下面,我们就来简单地介绍下mock方法时的参数匹配。

一、精确匹配

  还是先来看下被测试代码:

public class EmployeeService {
    public Employee findEmployeeByEmail(String email) {
        throw new UnsupportedOperationException();
    }

    public boolean employeeExists(Employee employee) {
        throw new UnsupportedOperationException();
    }
}
public class EmployeeController {
    private EmployeeService employeeService;

    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    public Employee findEmployeeByEmail(String email) {
        return employeeService.findEmployeeByEmail(email);
    }

    public boolean isEmployeeEmailAlreadyTaken(String email) {
        return employeeService.employeeExists(new Employee(email));
    }
}

  代码很直观,EmployeeController类中定义了两个方法,一个是findEmployeeByEmail,根据email查询员工,调用employeeService.findEmployeeByEmail方法;另一个方法是isEmployeeEmailAlreadyTaken方法,判断某个员工是否存在,调用employeeService.employeeExists方法。
  
  现在看下测试代码:

public class EmployeeControllerTest {
    @Test
    public void testFindEmployeeByEmail() {
        EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
        Employee employee = new Employee();
        PowerMockito.when(employeeService.findEmployeeByEmail(Mockito.eq("123@abc.com"))).thenReturn(employee);

        EmployeeController employeeController = new EmployeeController(employeeService);

        Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@abc.com"));
        Assert.assertNull(employeeController.findEmployeeByEmail("123@dce.com"));
    }
}

  从上述测试方法可以看到,在模拟employeeService.findEmployeeByEmail方法时使用了eq方法,这个就是精确匹配模式,执行参数完全匹配该参数时,才会返回employee。

二、模糊匹配

  有时候,我们想要在匹配参数时更灵活些,可以使用模糊匹配。看下下面的测试方法:

public class EmployeeControllerTest {
    @Test
    public void testFindEmployeeByEmail() {
        EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
        Employee employee = new Employee();
        PowerMockito.when(employeeService.findEmployeeByEmail(Mockito.startsWith("123"))).thenReturn(employee);

        EmployeeController employeeController = new EmployeeController(employeeService);

        Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@abc.com"));
        Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@dce.com"));
        Assert.assertNull(employeeService.findEmployeeByEmail("456@abc.com"));
    }
}

  该例中,使用startWith替换了eq,可以看到当参数为"123@abc.com"和"123@456.com"时,都返回了employee,而"456@abc.com"则返回了Null。可见此时参数是匹配任何以"123"开头的字符串,这种用法能够使得参数的匹配相对于eq方式更灵活些。

三、任意匹配

  另外一种参数匹配,即无论入参是什么值,都认为是匹配的。

public class EmployeeControllerTest {
    @Test
    public void testFindEmployeeByEmail() {
        EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
        Employee employee = new Employee();
        PowerMockito.when(employeeService.findEmployeeByEmail(Mockito.anyString())).thenReturn(employee);

        EmployeeController employeeController = new EmployeeController(employeeService);

        Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@abc.com"));
        Assert.assertSame(employee, employeeController.findEmployeeByEmail("123@dce.com"));
        Assert.assertSame(employee, employeeService.findEmployeeByEmail("456@abc.com"));
    }
}

  此例中,使用了anyString方式,即无论入参是什么字符串,都返回employee。此时可以看出给定的三个字符串,都返回了employee。

四、自定义匹配

  除了使用自带的匹配方式之外,还可以自己定义相应的参数匹配方式。

public class EmployeeControllerTest {
    @Test
    public void testIsEmployeeEmailAlreadyTaken() {
        EmployeeService employeeService = PowerMockito.mock(EmployeeService.class);
        final String email = "123@abc.com";
        PowerMockito.when(employeeService.employeeExists(Mockito.argThat(new ArgumentMatcher<Employee>() {
            @Override
            public boolean matches(Object employee) {
                return ((Employee) employee).getEmail().equals(email);
            }
        }))).thenReturn(true);

        EmployeeController employeeController = new EmployeeController(employeeService);

        Assert.assertTrue(employeeController.isEmployeeEmailAlreadyTaken(email));
    }
}

  这个例子看上去稍微有点复杂。从业务代码可以看出,EmployeeController类的方法isEmployeeEmailAlreadyTaken和EmployeeService类的方法参数并不一样,但是又有所关联,是使用isEmployeeEmailAlreadyTaken的入参构造了一个新的入参。现在,我们要想精确匹配入参,就需要自己实现matcher方法。

  除了上述的一些例子外,Mockito还提供了许多别的参数匹配的方法,比如any、matches、isNull等等。如何使用这些匹配方式,需要根据自己的需求来选择相应的模式实现。另外,上面介绍的参数匹配同样适用于Mockito.verify。

  最后,强调一点,对于多个参数的方法,如果我们其中一个参数使用了参数匹配模式,那么所有的参数都必须使用参数匹配模式,下面的例子中的使用方式就是错误的:

PowerMockito.when(mock.findEmployeeByFirstNameAndLastName("Deep", Mockito.anyString())).thenReturn(null);

  正确的方式为:

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

推荐阅读更多精彩内容

  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,146评论 0 3
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,638评论 18 139
  • 一、Java 简介 Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计...
    子非鱼_t_阅读 4,164评论 1 44
  • 阅读艺术的精髓在于不断提出问题并尝试精确正确地回答问题。我们可以以笔记的形式来对待这些问题,你需要把答案写出来,因...
    大汉养生阅读 469评论 0 0
  • 爸爸在那里种过菜,种过粮,也种过各种水果,但是他种出来的桃子是最好吃的。早桃面而甜,不乱核儿皮子也能轻松剥落,来买...
    阿尔他霞阅读 1,596评论 18 29