单元测试之Power Mock

这篇具有很好参考价值的文章主要介绍了单元测试之Power Mock。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

  • EasyMock、Mockito、jMock(单元测试模拟框架)
    在有这些模拟框架之前,程序员为了编写某一个函数的单元测试,必须进行十分繁琐的初始化工作,以确保调用的接口或编写的代码得到预期的结果。单元测试模拟框架极大的简化了单元测试的编写过程,在被测试代码需要调用某些接口的时候,直接模拟一个假的接口,并任意指定该接口的行为。这样就可以大大的提高单元测试的效率以及单元测试代码的可读性。
    **缺点:**都不可以实现对静态函数、构造函数、私有函数、Final函数以及系统函数的模拟,但是这些方法往往是我们在大型系统中需要的功能
  • Power Mock
    PowerMock 是在EasyMock以及Mockito基础上的扩展,通过定制类加载等技术,PowerMock实现了之前提到的所有模拟功能,使其成为大型系统上单元测试中的必备工具。
  • Mock
    Mock的意思是模拟,就是模拟接口返回的信息,用已有的信息替换它需要返回的信息,从而实现对上级模块的测试、

二、依赖

<properties>
        <powermock.version>1.6.6</powermock.version>
</properties>
<dependencies>
		<dependency>
			    <groupId>org.powermock</groupId>
			    <artifactId>powermock-module-junit4</artifactId>
			    <version>${powermock.version}</version>
			    <scope>test</scope>
		</dependency>
		<dependency>
			    <groupId>org.powermock</groupId>
			    <artifactId>powermock-api-mockito</artifactId>
			    <version>${powermock.version}</version>
			    <scope>test</scope>
		</dependency>
</dependencies>

三、相关注解

@RunWith(PowerMockRunner.class)
@PrepareForTest({UserController.class, CommonUtils.class})
@PowerMockIgnore("javax.management.*")
public class UserController {
    @Mock
    private UserService userService;
    @InjectMocks
    private  UserController userController = new UserController();
}
  • @RunWith(PowerMockRunner.class)
    表明用PowerMockerRunner来测试用例,否则无法使用PowerMock
  • @PrepareForTest({UserController.class, CommonUtils.class})
    所有需要测试的类,列在此处,以逗号分隔;在运行测试用例时,会创建一个新的org.powermock.core.classloader.MockClassLoader实例,然后加载该测试用例使用到的类
  • @PowerMockIgnore(“javax.management.*”)
    为了解决使用powermock后,提示classloader错误
  • @Mock
    注解修饰会mock出来一个userService对象
  • @InjectMocks
    注解会主动将已存在的mock对象注入到bean中,按名称注入,这个注解修饰在我们需要测试的类上。必须要手动new一个实例,不然单元测试会有问题。

四、使用(示例代码在文末)

  • PowerMockito.mock():
    指定需要mock的类型类(接口或者实现类),生成Mock类,其中所有的方法都不是真实的方法,访问对象方法不会执行具体逻辑,而且返回值都是NULL或者Empty。
    使用打桩返回给定数据:PowerMockito.when().thenReturn()方法
    若要执行具体逻辑:PowerMockito.when().thenCallRealMethod()方法
  • PowerMockito.spy():
    spy机制可以监视一个真实对象,对其进行方法调用会执行真实逻辑;
    spy也可以打桩指定的方法。
    spy中使用都Return…when打桩,不会执行具体逻辑
    spy中使用when…thenReturn打桩,会执行具体逻辑
  • mock有返回值的普通方法
@Test
 public void test_addUser(){
     User user = new User();
     PowerMockito.when(userService.addUser(user)).thenReturn(1);
     boolean result = userController.addUser(user);
     Assert.assertEquals(result, true);
 }

注:userService.addUser()和userController.addUser()所使用的参数值必须保持一致

  • mock无返回值的普通方法
    方法一:
 @Test
 public void test_initUser() throws Exception {
     User user = new User();
     user.setId(111);
     PowerMockito.doNothing().when(userService, "initUser", user);
     User result = userController.initUser(user);
     Assert.assertEquals(result.getId(), 111);
 }

方法二:

@Test
public void test_initUser1() throws Exception {
    User user = new User();
    user.setId(111);
    PowerMockito.doNothing().when(userService).initUser(user);
    User result = userController.initUser(user);
    Assert.assertEquals(result.getId(), 111);
}
  • mock抛异常
@Test
public void test_delUser() throws Exception {
    PowerMockito.when(userService.delUser(1)).thenThrow(new Exception("删除失败"));
    boolean result = userController.delUser(1);
    Assert.assertEquals(result, false);
}

注:thenThrow()中抛出delUser()方法抛出的异常或其子异常

  • mock静态方法
@Test
public void test_append() {
     PowerMockito.mockStatic(CommonUtils.class);
     PowerMockito.when(CommonUtils.isNotEmpty("World")).thenReturn(false);
     String result = userController.append("World");
     Assert.assertEquals(result, "Hello");
 }

注:需要在@PrepareForTest注解中加上CommonUtils.class

  • mock返回值为void的static方法
    方法一:
@Test
public void test_getFile() throws Exception {
   String filePath = "xiaofeng";
    PowerMockito.mockStatic(CommonUtils.class);
    PowerMockito.doNothing().when(CommonUtils.class, "validFilePath", filePath);
    File result = userController.getFile(filePath);
    Assert.assertEquals(result.getName(), filePath);
}

方法二:

@Test
public void test_getFile1() throws Exception {
    String filePath = "xiaofeng";
    PowerMockito.mockStatic(CommonUtils.class);
    PowerMockito.doNothing().when(CommonUtils.class);
    CommonUtils.validFilePath(filePath);
    File result = userController.getFile(filePath);
    Assert.assertEquals(result.getName(), filePath);
}
  • mock私有方法
    方法一:
@Test
public void test_modUser() throws Exception {
   User user = new User();
    PowerMockito.when(userService.modUser(user)).thenReturn(1);
    UserController controller = PowerMockito.mock(UserController.class);
    // 给没有set方法的私有属性赋值
    Whitebox.setInternalState(controller, "userService", userService);
    // 因为要测试的是modUser()方法,所以调用这个方法时,应调用真实方法,并非mock掉的方法
    PowerMockito.when(controller.modUser(user)).thenCallRealMethod();
    // 在modUser()方法中会调用verifyMod()这个私有方法,所以将其mock掉
    PowerMockito.when(controller, "verifyMod", 1).thenReturn(false);
    boolean result = controller.modUser(user);
    Assert.assertEquals(result, false);
}

注:此处的controller是mock出来的,不是UserControllerTest类中的成员变量userController(不会执行verifyMod方法,直接返回模拟值)
方法二:

@Test
public void test_modUser1() throws Exception {
    User user = new User();
    PowerMockito.when(userService.modUser(user)).thenReturn(1);
    // 对userController进行监视
    UserController controller = PowerMockito.spy(userController);
    // 当userController的verifyMod被执行时,将被mock掉
    PowerMockito.when(controller, "verifyMod", 1).thenReturn(false);
    boolean result = controller.modUser(user);
    Assert.assertEquals(result, false);
}

注:spy方法可以避免执行被测类中的成员函数,即mock掉不想被执行的私有方法(会执行verifyMod方法,但是会返回模拟值)

  • 测试私有方法(注意:是测试,不是mock)
    方法一:
@Test
public void test_verifyMod() throws Exception {
   // 获取method方法
    Method method = PowerMockito.method(UserController.class, "verifyMod", Integer.class);
    // 调用Method的invoke方法来执行
    boolean result = (boolean) method.invoke(userController, 1);
    Assert.assertEquals(result, true);
}

方法二:文章来源地址https://www.toymoban.com/news/detail-403387.html

@Test
public void test_verifyMod1() throws Exception {
   // 直接通过Whitebox来执行
    boolean result = Whitebox.invokeMethod(userController, "verifyMod", 1);
    Assert.assertEquals(result, true);
}
  • mock新建对象
@Test
public void test_getUser() throws Exception {
   User user = new User();
    user.setName("大风");
    PowerMockito.whenNew(User.class).withNoArguments().thenReturn(user);
    User result = userController.getUser();
    Assert.assertEquals(result.getName(), "大风");
}
  • mock同一方法,返回不同的值
@Test
public void test_getString() throws Exception {
    UserController controller = PowerMockito.spy(userController);
    PowerMockito.when(controller, "getFlag").thenReturn(true, false);
    String result = controller.getString("Hello");
    Assert.assertEquals(result, "Hello");
}
  • mock final方法
    final与普通方法一样mock,但是需要将其所在class添加到@PrepareForTest注解中
  • 参数的模糊匹配
    org.mockito.Matchers类中,提供了很多any*的方法,如anyObject()、anyString()…我们可以使用这些方法去避免构建那些难以模拟的输入参数
    注:如果对某一个参数使用了Matcher,那么这个方法的所有其它参数也必须使用Matcher,否则将会报错。

五、示例代码

package com.example.pattren.junitTest;

public class User {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.example.pattren.junitTest;

public interface UserService {
    int addUser(User user);

    void initUser(User user);

    int delUser(int id) throws Exception;

    int modUser(User user);
}
package com.example.pattren.junitTest;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.text.Normalizer;

public class CommonUtils {
    public static boolean isEmpty(CharSequence cs) {
        return cs == null || cs.length() == 0;
    }

    public static boolean isNotEmpty(CharSequence cs) {
        return !isEmpty(cs);
    }

    public static void validFilePath(String filePath) throws IOException {
        if (CommonUtils.isEmpty(filePath)) {
            throw new IOException("the file path is empty");
        }
        filePath = Normalizer.normalize(filePath, Normalizer.Form.NFKC);
        File file = new File(filePath);
        String decode = URLDecoder.decode(file.getCanonicalPath(), "UTF-8");
        file = new File(decode);
        if (!file.exists()) {
            throw new IOException("the file path is not exists");
        }
    }
}
package com.example.pattren.junitTest;

import java.io.File;
import java.io.IOException;

public class UserController {
    private UserService userService;

    public boolean addUser(User user) {
        int i = userService.addUser(user);
        if (i <= 0) {
            return false;
        } else {
            return true;
        }
    }

    public User initUser(User user) {
        userService.initUser(user);
        return user;
    }

    public boolean delUser(int id) {
        try {
            userService.delUser(id);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public String append(String param) {
        String str = "Hello";
        if (CommonUtils.isNotEmpty(param)) {
            return str + param;
        } else {
            return str;
        }
    }

    public File getFile(String filePath) throws IOException {
        CommonUtils.validFilePath(filePath);
        return new File(filePath);
    }

    public boolean modUser(User user) {
        int flag = userService.modUser(user);
        return verifyMod(flag);
    }

    private boolean verifyMod(Integer flag) {
        if (flag > 0) {
            return true;
        }
        return false;
    }

    public User getUser() {
        User user = new User();
        return user;
    }

    public String getString(String str) {
        StringBuffer result = new StringBuffer();
        while (this.getFlag()) {
            result.append(str);
        }
        return result.toString();
    }

    private boolean getFlag() {
        return true;
    }
}
package com.example.pattren.junitTest;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;

import java.io.File;
import java.lang.reflect.Method;

@RunWith(PowerMockRunner.class)
@PrepareForTest({UserController.class, CommonUtils.class})
@PowerMockIgnore("javax.management.*")
public class UserControllerTest {
    @Mock
    private UserService userService;
    @InjectMocks
    private UserController userController = new UserController();

    /**
     * mock有返回值的普通方法
     */
    @Test
    public void test_addUser() {
        User user = new User();
        PowerMockito.when(userService.addUser(user)).thenReturn(1);
        boolean result = userController.addUser(user);
        Assert.assertEquals(result, true);
    }

    /**
     * mock无返回值的普通方法    (方法一)
     */
    @Test
    public void test_initUser() throws Exception {
        User user = new User();
        user.setId(111);
        PowerMockito.doNothing().when(userService, "initUser", user);
        User result = userController.initUser(user);
        Assert.assertEquals(result.getId(), 111);
    }

    /**
     * mock有无返回值的普通方法    (方法二)
     */
    @Test
    public void test_initUser1() throws Exception {
        User user = new User();
        user.setId(111);
        PowerMockito.doNothing().when(userService).initUser(user);
        User result = userController.initUser(user);
        Assert.assertEquals(result.getId(), 111);
    }

    /**
     * mock抛异常
     */
    @Test
    public void test_delUser() throws Exception {
        PowerMockito.when(userService.delUser(1)).thenThrow(new Exception("删除失败"));
        boolean result = userController.delUser(1);
        Assert.assertEquals(result, false);
    }

    /**
     * mock静态方法
     */
    @Test
    public void test_append() {
        PowerMockito.mockStatic(CommonUtils.class);
        PowerMockito.when(CommonUtils.isNotEmpty("World")).thenReturn(false);
        String result = userController.append("World");
        Assert.assertEquals(result, "Hello");
    }

    /**
     * mock返回值为void的static方法     (方法一)
     */
    @Test
    public void test_getFile() throws Exception {
        String filePath = "xiaofeng";
        PowerMockito.mockStatic(CommonUtils.class);
        PowerMockito.doNothing().when(CommonUtils.class, "validFilePath", filePath);
        File result = userController.getFile(filePath);
        Assert.assertEquals(result.getName(), filePath);
    }

    /**
     * mock返回值为void的static方法     (方法二)
     */
    @Test
    public void test_getFile1() throws Exception {
        String filePath = "xiaofeng";
        PowerMockito.mockStatic(CommonUtils.class);
        PowerMockito.doNothing().when(CommonUtils.class);
        CommonUtils.validFilePath(filePath);
        File result = userController.getFile(filePath);
        Assert.assertEquals(result.getName(), filePath);
    }

    /**
     * mock私有方法     (方法一)
     */
    @Test
    public void test_modUser() throws Exception {
        User user = new User();
        PowerMockito.when(userService.modUser(user)).thenReturn(1);
        UserController controller = PowerMockito.mock(UserController.class);
        // 给没有set方法的私有属性赋值
        Whitebox.setInternalState(controller, "userService", userService);
        // 因为要测试的是modUser()方法,所以调用这个方法时,应调用真实方法,并非mock掉的方法
        PowerMockito.when(controller.modUser(user)).thenCallRealMethod();
        // 在modUser()方法中会调用verifyMod()这个私有方法,所以将其mock掉
        PowerMockito.when(controller, "verifyMod", 1).thenReturn(false);
        boolean result = controller.modUser(user);
        Assert.assertEquals(result, false);
    }

    /**
     * mock私有方法     (方法二)
     */
    @Test
    public void test_modUser1() throws Exception {
        User user = new User();
        PowerMockito.when(userService.modUser(user)).thenReturn(1);
        // 对userController进行监视
        UserController controller = PowerMockito.spy(userController);
        // 当userController的verifyMod被执行时,将被mock掉
        PowerMockito.when(controller, "verifyMod", 1).thenReturn(false);
        boolean result = controller.modUser(user);
        Assert.assertEquals(result, false);
    }

    /**
     * 测试私有方法(注意:是测试,不是mock)     (方法一)
     */
    @Test
    public void test_verifyMod() throws Exception {
        // 获取method方法
        Method method = PowerMockito.method(UserController.class, "verifyMod", Integer.class);
        // 调用Method的invoke方法来执行
        boolean result = (boolean) method.invoke(userController, 1);
        Assert.assertEquals(result, true);
    }

    /**
     * 测试私有方法(注意:是测试,不是mock)     (方法二)
     */
    @Test
    public void test_verifyMod1() throws Exception {
        // 直接通过Whitebox来执行
        boolean result = Whitebox.invokeMethod(userController, "verifyMod", 1);
        Assert.assertEquals(result, true);
    }

    /**
     * mock新建对象
     */
    @Test
    public void test_getUser() throws Exception {
        User user = new User();
        user.setName("大风");
        PowerMockito.whenNew(User.class).withNoArguments().thenReturn(user);
        User result = userController.getUser();
        Assert.assertEquals(result.getName(), "大风");
    }

    /**
     * mock同一方法,返回不同的值
     */
    @Test
    public void test_getString() throws Exception {
        UserController controller = PowerMockito.spy(userController);
        PowerMockito.when(controller, "getFlag").thenReturn(true, false);
        String result = controller.getString("Hello");
        Assert.assertEquals(result, "Hello");
    }
}

到了这里,关于单元测试之Power Mock的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 高效单元测试——EasyMock技术与应用

    目录 1.EasyMock 简介 2.EasyMock 实例 3.EasyMock 模型 3.1、record-replay-verify 模型 3.2、record  3.3、replay  3.4、verify 3.5、easymock部分功能说明 2. 记录mock对象期望的行为 4.EasyMock 应用 4.1、Easymock对AccountService进行测试 4.2、用Easymock对WebClient的测试  ​编辑 Mock 对象的弊端? 手动的构造 Moc

    2024年02月01日
    浏览(31)
  • Mockito单元测试详解

    依赖: SpringBoot默认的Mock框架是Mockito,和junit一样,只需要依赖spring-boot-starter-test就可以了 (1)@RunWith 指定运行环境,例: @RunWith(SpringRunner.class) Junit运行Spring的测试环境 @RunWith(MockitoJUnitRunner.class) Junit运行Mockito的运行环境,不会加载springboot上下文 @SpringBootTest 加载springbo

    2023年04月09日
    浏览(41)
  • Mockito单元测试异常情况

    一、空指针异常 例子: 使用Collectors.groupingBy()进行分组时, 分组值存在null值 。 解决办法:分组值为null时,默认值为空字符,或者让数据不为空。 二、多个参数匹配异常 例如: 如果a和b一个是正常传参(list、map、string…)另一个是任意万能传参(any()、anyList()、anyString(

    2024年02月07日
    浏览(51)
  • 单元测试Mockito

    Mockito 1.为什么要mock? mock等于是创建一个虚拟对象(不会去跑真实的),在测试环境中替换掉真是对象,从而 验证该对象某些方法的调用情况,调用多少次,参数等 给对象做一个定义,指定返回结果或者特定的动作 2.什么是mock,stub和spy mock: Mock 对象是一种完全由测试控制

    2024年03月18日
    浏览(42)
  • 单元测试-mockito

    在单元测试中,对于一个类中的方法,常常需要依赖其他类的方法、操作数据dto等对象实例。 方法mock:依赖的方法又可能依赖其他方法,呈现级联的树状结构。 问题:在一些情况下,这个依赖树会很深,其中依赖的一个子方法一旦修改出现问题,如果引起大量的单测不可用

    2024年04月11日
    浏览(71)
  • Spring单元测试+Mockito

    一,背景 单元测试基本上是开发逃不过的一个工作内容,虽然往往因为过于无聊,或者过于麻烦,而停止于项目的迭代之中,不了了之了。其实不是开发们懒,而是上头要求的测试覆盖率高,但是又没有好用的工具,导致工作积压,最后只能舍弃掉这部分。 最近发现Spring+

    2024年04月17日
    浏览(43)
  • 【单元测试】Mockito使用详解

    一个单元测试应该有如下特点: 应该是自动化的 应该可以快速运行 每个单元测试不应该依赖其它测试的结果和执行顺序,单元测试框架可以按任意的顺序执行每个测试 每个单元测试不应该依赖数据库,外部文件,或者任何长时间运行的任务。单元测试应该是独立的,不应该

    2024年04月15日
    浏览(87)
  • 单元测试与Mockito

    系列文章目录和关于我 最近在新公司第一次上手写代码,写了一个不是很难的业务逻辑代码,但是在我写单元测试的时候,发现自己对单元测试的理解的就是一坨,整个过程写得慢,还写得臭。造成这种局面我认为是因为: 对Mockito api是不是很熟悉 没有自己单元测试方法论

    2023年04月22日
    浏览(41)
  • Mockito单元测试基本使用

    本文参考: 【码农教程】手把手教你Mockito的使用 - 掘金 (juejin.cn) java - doReturn().when()与when().thenReturn() - 成长之路 - SegmentFault 思否 单元测试实践篇:Mock_阿里巴巴淘系技术团队官网博客的博客-CSDN博客 阿里是如何进行单元测试培训的?_Hollis Chuang的博客-CSDN博客 【Mockito】Mock

    2024年02月10日
    浏览(50)
  • Java单元测试之Mockito

    Mockito是一种Java Mock框架,主要就是用来做Mock测试的,它可以模拟任何Spring管理的Bean、模拟方法的返回值、模拟抛出异常等等,同时也会记录调用这些模拟方法的参数、调用顺序,从而可以校验出这个Mock对象是否有被正确的顺序调用,以及按照期望的参数被调用。 Mockito的特

    2024年02月13日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包