【Java】使用PowerMockito mock static方法/new对象/mock对象的public或private方法的简单示例

这篇具有很好参考价值的文章主要介绍了【Java】使用PowerMockito mock static方法/new对象/mock对象的public或private方法的简单示例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.针对方法打桩

1.1 打桩类的public static方法

测试用例中如果需要对public静态方法的打桩,针对测试类增加注解@RunWith(PowerMockRunner.class)同时针对静态方法所在的类增加注解@PrepareForTest({StaticMethod.class}),接着在测试用例调用方法之前增加

PowerMockito.mockStatic(StaticMethod.class);
PowerMockito.when(StaticMethod.getJavaVersion()).thenReturn(“1.8.0_92”); 或者用写法
PowerMockito.doReturn(“1.8.0_92”).when(StaticMethod.class, “getJavaVersion”);
另外对PowerMockito的调用最好在产品类ProductClass对象new之前进行,这样保障一切模拟数据就绪后再进行产品类的测试,保证测试用例一次性成功编写的几率。

import junit.framework.TestCase;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({StaticMethod.class})
public class ProductClassTest extends TestCase {
    public void test_getCustomNameByVersion() {
        PowerMockito.mockStatic(StaticMethod.class);
        PowerMockito.when(StaticMethod.getJavaVersion()).thenReturn("1.8.0_92");
        ProductClass product = new ProductClass();
        assertEquals("18VersionSeries", product.getCustomNameByVersion());
    }
}

ProductClassTest.java
public class ProductClass {
    public String getCustomNameByVersion() {
        String javaVersion = StaticMethod.getJavaVersion();
        if(javaVersion.split("_")[0].contains("1.8")) {
            return "18VersionSeries";
        }
        else {
            return "OTHER";
        }
    }
}

ProductClass.java产品代码调用其他类的静态方法
public class StaticMethod {
    public static String getJavaVersion() {
        throw new RuntimeException();
    }
}

1.2 打桩类的private static方法

针对StaticMethod类中的private static方法打桩的时候,外部调用StaticMethod类的public方法仍然保持实际代码的调用,因此在模拟private static方法之前,增加一行

PowerMockito.spy(StaticMethod.class);或者

PowerMockito.when(StaticMethod.getJavaVersion()).thenCallRealMethod();
以此保证除了具体的某个方法打桩,其他的方法保持照旧。另外,针对private方法,因为正常是无法直接访问的,因此需要使用

下面的形式进行调用。这里要注意一个事情,doReturn when 和 when thenReturn的差异,后者是虽然做了打桩但是实际的代码还是会走一遍。

PowerMockito.doReturn(true).when(StaticMethod.class, “isProduct”);

import junit.framework.TestCase;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({StaticMethod.class})
public class ProductClassTest extends TestCase {
    
    public void test_getCustomNameByVersion_product() throws Exception {
        PowerMockito.mockStatic(StaticMethod.class);
        PowerMockito.spy(StaticMethod.class);
        PowerMockito.doReturn(true).when(StaticMethod.class, "isProduct");

        ProductClass product = new ProductClass();
        assertEquals("18VersionSeries", product.getCustomNameByVersion());
    }
}

ProductClassTest.java测试用例
public class StaticMethod {
    public static String getJavaVersion() {
        if (isProduct()) {
            System.out.println("getJavaVersion()::product");
            return System.getProperty("java.version");
        }
        System.out.println("getJavaVersion()::test");
        throw new RuntimeException();
    }

    private static boolean isProduct() {
        if (System.getenv().containsKey("isProduct=false")) {
            System.out.println("isProduct()::false");
            return false;
        } else {
            System.out.println("isProduct()::true");
            return true;
        }
    }
}

StaticMethod.java
public class ProductClass {
    public String getCustomNameByVersion() {
        String javaVersion = StaticMethod.getJavaVersion();
        if(javaVersion.split("_")[0].contains("1.8")) {
            return "18VersionSeries";
        }
        else {
            return "OTHER";
        }
    }
}

ProductClass.java

1.3 打桩类的public方法实现部分中使用的new对象

如果要对 StudentHandler.java的new对象进行mock,那么需要把StudentHandler对象所在的类StudentMng放到 @PrepareForTest({StudentMng.class})

需要特别注意,在PrepareForTest中放的类在统计代码覆盖率的时候,覆盖率是0。如果要针对该类进行代码测试覆盖,那需要以其他的方式进行模拟测试。

1 package training;
 2 
 3 import junit.framework.TestCase;
 4 import org.junit.runner.RunWith;
 5 import org.powermock.api.mockito.PowerMockito;
 6 import org.powermock.core.classloader.annotations.PrepareForTest;
 7 import org.powermock.modules.junit4.PowerMockRunner;
 8 
 9 
10 import java.util.ArrayList;
11 import java.util.List;
12 @RunWith(PowerMockRunner.class)
13 @PrepareForTest({StudentMng.class})
14 public class StudentMngTest extends TestCase {
15 
16 
17         public void test_getSpecifiedStudents() throws Exception {
18             StudentHandler handler = PowerMockito.mock(StudentHandler.class);
19             PowerMockito.when(handler.getAllStudents()).thenReturn(mockStudents());
20             PowerMockito.whenNew(StudentHandler.class).withNoArguments().thenReturn(handler);
21             StudentMng mng = new StudentMng();
22             assertEquals(1, mng.getSpecifiedStudents(10).size());
23     }
24 
25     private List<Student> mockStudents() {
26         List<Student> students = new ArrayList<>();
27         Student stu = new Student();
28         stu.setScore(new Score(80, 11));
29         students.add(stu);
30         return students;
31     }
32 }

StudentMngTest.java
1 package training;
 2 
 3 import java.util.List;
 4 
 5 public class StudentHandler {
 6     public StudentHandler() {
 7         System.out.println("invoke StudentHandler()");
 8         throw new RuntimeException();
 9     }
10     public List<Student> getAllStudents() {
11         System.out.println("invoke getAllStudents");
12         throw new RuntimeException();
13     }
14 }

StudentHandler.java 是一个不方便直接new的类
1 package training;
 2 
 3 public class Student {
 4     private String sno;
 5     private String name;
 6     private Score score = new Score(100, 1000);
 7 
 8     public String getName() {
 9         System.out.println("invoke getName");
10         return name;
11     }
12 
13     public void setName(String name) {
14         System.out.println("invoke setName");
15         this.name = name;
16     }
17 
18     public String getSno() {
19         System.out.println("invoke getSno");
20         return sno;
21     }
22 
23     public void setSno(String sno) {
24         System.out.println("invoke setSno");
25         this.sno = sno;
26     }
27 
28     public void setScore(Score score) {
29         System.out.println("invoke setScore");
30         this.score = score;
31     }
32 
33     public Score getScore() {
34         System.out.println("invoke getScore");
35         return score;
36     }
37 
38     public String getScoreRecord(int delta) {
39         System.out.println("invoke getScoreRecord");
40         return String.format("sno:%s,name:%s,value:%d,level:%d", sno, name, score.getValue() + delta, score.getLevel());
41     }
42 }

Student.java
1 package training;
 2 
 3 public class Score {
 4     private int value;
 5     private int level;
 6 
 7     public Score(int value, int level) {
 8         this.value = value;
 9         this.level =  level;
10     }
11 
12     public int getLevel() {
13         System.out.println("invoke getLevel");
14         return level;
15     }
16 
17     public void setLevel(int level) {
18         System.out.println("invoke setLevel");
19         this.level = level;
20     }
21 
22     public int getValue() {
23         System.out.println("invoke getValue");
24         return value;
25     }
26 
27     public void setValue(int value) {
28         System.out.println("invoke setValue");
29         this.value = value;
30     }
31 }

Score.java

1.4打桩类的public方法

2种方式,方式一:PowerMockito.mock方式,对应StudentTest.java中的test_mock_public_method_powermock()测试用例
方式二:函数复写override方式,对应StudentTest.java中的test_mock_public_method_override()测试用例

两种方式比较,方式一代码看起来简洁。 方式二 测试用例运行时间效率很高。

1 package training;
 2 
 3 import junit.framework.TestCase;
 4 import org.powermock.api.mockito.PowerMockito;
 5 
 6 public class StudentTest extends TestCase {
 7     public void test_mock_public_method_powermock()
 8     {
 9         Student stu = PowerMockito.mock(Student.class);
10         PowerMockito.when(stu.getName()).thenReturn("test_name");
11         PowerMockito.when(stu.getNewName()).thenCallRealMethod();
12         assertEquals("new_test_name", stu.getNewName());
13     }
14 
15     public void test_mock_public_method_override()
16     {
17         Student stu = new Student() {
18             @Override
19             public String getName() {
20                 return "test_name";
21             }
22         };
23         assertEquals("new_test_name", stu.getNewName());
24     }
25 }

StudentTest.java
1 package training;
 2 
 3 public class Student {
 4     private String name;
 5     
 6 
 7     public String getName() {
 8         System.out.println("invoke getName");
 9         throw new RuntimeException();
10 //        return name;
11     }
12 
13     public String getNewName() {
14         System.out.println("invoke getNewName");
15         return "new_" + getName();
16     }
17     
18 }

Student.java

1.5 打桩类的private方法

Student.java类中getName方法为private的,因此需要使用PowerMockito.when(stu, “getName”).thenReturn(“test_name”); 方式进行mock。

被模拟的Student类需要在测试用例test类的开头增加以下两行。

@RunWith(PowerMockRunner.class)
@PrepareForTest({Student.class})

1 package training;
 2 
 3 import junit.framework.TestCase;
 4 import org.junit.runner.RunWith;
 5 import org.powermock.api.mockito.PowerMockito;
 6 import org.powermock.core.classloader.annotations.PrepareForTest;
 7 import org.powermock.modules.junit4.PowerMockRunner;
 8 
 9 @RunWith(PowerMockRunner.class)
10 @PrepareForTest({Student.class})
11 public class StudentTest extends TestCase {
12     public void test_mock_public_method_powermock()
13     {
14         Student stu = PowerMockito.mock(Student.class);
15         try {
16             PowerMockito.when(stu, "getName").thenReturn("test_name");
17         } catch (Exception e) {
18             e.printStackTrace();
19         }
20         PowerMockito.when(stu.getNewName()).thenCallRealMethod();
21         assertEquals("new_test_name", stu.getNewName());
22     }
23 
24 }

StudentTest.java
1 package training;
 2 
 3 public class Student {
 4     private String sno;
 5     private String name;
 6     private Score score = new Score(100, 1000);
 7 
 8     private String getName() {
 9         System.out.println("invoke getName");
10         throw new RuntimeException();
11 //        return name;
12     }
13 
14     public String getNewName() {
15         System.out.println("invoke getNewName");
16         return "new_" + getName();
17     }
18 
19     public void setName(String name) {
20         System.out.println("invoke setName");
21         this.name = name;
22     }
23 
24     public String getSno() {
25         System.out.println("invoke getSno");
26         return sno;
27     }
28 
29     public void setSno(String sno) {
30         System.out.println("invoke setSno");
31         this.sno = sno;
32     }
33 
34     public void setScore(Score score) {
35         System.out.println("invoke setScore");
36         this.score = score;
37     }
38 
39     public Score getScore() {
40         System.out.println("invoke getScore");
41         return score;
42     }
43 
44     public String getScoreRecord(int delta) {
45         System.out.println("invoke getScoreRecord");
46         return String.format("sno:%s,name:%s,value:%d,level:%d", sno, name, score.getValue() + delta, score.getLevel());
47     }
48 }

Student.java

2.针对变量打桩

2.1 打桩类的private成员变量

方法一: Whitebox

来源StudentMngTest.java,关键模拟代码如下,Whitebox.setInternalState(mng, “handler”, handler);打桩设置对象的私有成员变量。

PowerMockito.when(mng.getSpecifiedStudents(10)).thenCallRealMethod();控制调用实际的方法。

StudentMng mng = PowerMockito.mock(StudentMng.class); 控制StudentMng对象的初始化过程,保证在对象初始化的时候不去做StudentHandler成员变量的初始化。

public void test_getSpecifiedStudents() {
StudentHandler handler = PowerMockito.mock(StudentHandler.class);
PowerMockito.when(handler.getAllStudents()).thenReturn(mockStudents());
StudentMng mng = PowerMockito.mock(StudentMng.class);
Whitebox.setInternalState(mng, “handler”, handler);
PowerMockito.when(mng.getSpecifiedStudents(10)).thenCallRealMethod();
assertEquals(1, mng.getSpecifiedStudents(10).size());
}

package training;

import junit.framework.TestCase;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.reflect.Whitebox;

import java.util.ArrayList;
import java.util.List;

public class StudentMngTest extends TestCase {
    public void test_getSpecifiedStudents() {
        StudentHandler handler = PowerMockito.mock(StudentHandler.class);
        PowerMockito.when(handler.getAllStudents()).thenReturn(mockStudents());
        StudentMng mng = PowerMockito.mock(StudentMng.class);
        Whitebox.setInternalState(mng, "handler", handler);
        PowerMockito.when(mng.getSpecifiedStudents(10)).thenCallRealMethod();
        assertEquals(1, mng.getSpecifiedStudents(10).size());
    }

    private List<Student> mockStudents() {
        List<Student> students = new ArrayList<>();
        Student stu = new Student();
        stu.setScore(new Score(80, 11));
        students.add(stu);
        return students;
    }
}

StudentMngTest.java 打桩后 连初始化StudentMng对象的时候都模拟完成。
package training;

import java.util.List;

public class StudentHandler {
    public StudentHandler() {
        System.out.println("invoke StudentHandler()");
//        throw new RuntimeException();
    }
    public List<Student> getAllStudents() {
        System.out.println("invoke getAllStudents");
        throw new RuntimeException();
    }
}

StudentHandler.java
package training;

public class Student {
    private String sno;
    private String name;
    private Score score = new Score(100, 1000);

    public String getName() {
        System.out.println("invoke getName");
        return name;
    }

    public void setName(String name) {
        System.out.println("invoke setName");
        this.name = name;
    }

    public String getSno() {
        System.out.println("invoke getSno");
        return sno;
    }

    public void setSno(String sno) {
        System.out.println("invoke setSno");
        this.sno = sno;
    }

    public void setScore(Score score) {
        System.out.println("invoke setScore");
        this.score = score;
    }

    public Score getScore() {
        System.out.println("invoke getScore");
        return score;
    }

    public String getScoreRecord(int delta) {
        System.out.println("invoke getScoreRecord");
        return String.format("sno:%s,name:%s,value:%d,level:%d", sno, name, score.getValue() + delta, score.getLevel());
    }
}

Student.java
package training;

public class Score {
    private int value;
    private int level;

    public Score(int value, int level) {
        this.value = value;
        this.level =  level;
    }

    public int getLevel() {
        System.out.println("invoke getLevel");
        return level;
    }

    public void setLevel(int level) {
        System.out.println("invoke setLevel");
        this.level = level;
    }

    public int getValue() {
        System.out.println("invoke getValue");
        return value;
    }

    public void setValue(int value) {
        System.out.println("invoke setValue");
        this.value = value;
    }
}

Score.java

方法二(更加通用):用以下方式修改属性的访问权限,另外 @PrepareForTest({StudentMng.class}) 和 PowerMockito.whenNew(StudentHandler.class).withNoArguments().thenReturn(handler); 同时来达到mock new对象的目的。

Field handlerField = mng.getClass().getDeclaredField(“handler”);
handlerField.setAccessible(true);
handlerField.set(mng, handler);

1 package training;
 2 
 3 import junit.framework.TestCase;
 4 import org.junit.runner.RunWith;
 5 import org.powermock.api.mockito.PowerMockito;
 6 import org.powermock.core.classloader.annotations.PrepareForTest;
 7 import org.powermock.modules.junit4.PowerMockRunner;
 8 
 9 import java.lang.reflect.Field;
10 import java.util.ArrayList;
11 import java.util.List;
12 
13 @RunWith(PowerMockRunner.class)
14 @PrepareForTest({StudentMng.class})
15 public class StudentMngTest extends TestCase {
16     public void test_getSpecifiedStudents() throws Exception {
17         StudentHandler handler = PowerMockito.mock(StudentHandler.class);
18         PowerMockito.when(handler.getAllStudents()).thenReturn(mockStudents());
19         PowerMockito.whenNew(StudentHandler.class).withNoArguments().thenReturn(handler);
20         StudentMng mng = new StudentMng();
21         Field handlerField = mng.getClass().getDeclaredField("handler");
22         handlerField.setAccessible(true);
23         handlerField.set(mng, handler);
24         assertEquals(1, mng.getSpecifiedStudents(10).size());
25     }
26 
27     private List<Student> mockStudents() {
28         List<Student> students = new ArrayList<>();
29         Student stu = new Student();
30         stu.setScore(new Score(80, 11));
31         students.add(stu);
32         return students;
33     }
34 }

StudentMngTest.java

2.2 打桩类的public static变量或者private static变量

针对此类情况,建议对static变量赋值的部分进行mock模拟,以此来达到模拟变量值得目的。

3.测试用例执行效率简单说明

override方式模拟打桩方式的执行测试用例时间消耗

< 不带@RunWith(PowerMockRunner.class)和@PrepareForTest({StudentMng.class}) 方式的执行测试用例时间消耗

< 只带@RunWith(PowerMockRunner.class)方式的的执行测试用例时间消耗

< 都带@RunWith(PowerMockRunner.class)和@PrepareForTest({StudentMng.class}) 方式的的执行测试用例时间消耗

关于代码覆盖率:在PrepareForTest中放的类在统计代码覆盖率的时候,覆盖率是0。如果要针对该类进行代码测试覆盖,

那需要以其他的方式进行模拟测试。

关于编写产品代码:建议在编写产品代码的时候,尽量按照对象注入方式,同时减少静态方法的实现方式,

以此也能增加代码的灵活性,同时在给编写测试用例也能带来较大的便利。文章来源地址https://www.toymoban.com/news/detail-821535.html

到了这里,关于【Java】使用PowerMockito mock static方法/new对象/mock对象的public或private方法的简单示例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 菜鸟学Java public static void main(String[] args) 是什么意思?

    这是一个经典的 Java 程序,它使用了面向对象的编程风格: 第一行代码: 这行代码定义了一个名为 HelloWorld 的公共类( public class ),该类是程序的入口点。 Java 程序中的每个类都必须以一个公共类来定义。文件名必须与公共类的名称相同,并以 .java 作为文件扩展名。 注:

    2024年02月09日
    浏览(11)
  • 我在VScode学Java类与对象(Java显式参数和隐式参数、静态方法+main方法、Java访问修饰符、static关键字、Java的包、对象数组)第三辑

    我在VScode学Java类与对象(Java显式参数和隐式参数、静态方法+main方法、Java访问修饰符、static关键字、Java的包、对象数组)第三辑

    我的个人博客主页:如果’\\\'真能转义1️⃣说1️⃣的博客主页 关于Java基本语法学习----可以参考我的这篇博客:《我在VScode学Java》 方法会操作对象并访问他们的实例字段。 在Java中,显式参数和隐式参数是方法调用中的两种不同类型的参数。 注释: 第7行: sum 方法的参数

    2024年02月16日
    浏览(51)
  • 深入理解JVM:Java使用new创建对象的流程

            ①new 对象         ②反射         ③对象的复制         ④反序列化 先看看常量池里面有没有,如果有,就用常量池的 看这个类有没有被加载过,如果没有,就执行类加载以及类的初始化。(对象的大小,在类加载的时候就确定了)。 对象在堆内存

    2024年02月15日
    浏览(14)
  • 黑马Java——面向对象进阶(static&继承)

    黑马Java——面向对象进阶(static&继承)

    目录 1.static静态变量 练习1:定义数组工具类 练习2:定义学生工具类 2.继承  练习:继承的练习(自己设计一个继承体系) 练习 利用方法的重写设计继承结构 练习:带有继承结构的标准Javabean类 3.多态   多态的综合练习 4.包和final 4.1包 4.2final  5.权限修饰符和代码块 5.1权

    2024年01月25日
    浏览(10)
  • 【java面向对象中static关键字】

    【java面向对象中static关键字】

    static修饰成员变量 static修饰成员变量的应用场景 static修饰成员方法 static修饰成员方法的应用场景 static的注意事项 static的应用知识:代码块 static的应用知识:单例设计模式 static静态的意思,可以修饰成员变量,成员方法; static修饰成员变量: 1.有static修饰的成员变量叫做

    2024年02月13日
    浏览(12)
  • java基础入门-05-【面向对象进阶(static&继承)】

    java基础入门-05-【面向对象进阶(static&继承)】

    类的定义格式如下: 例如: 例如: 1.3.1 封装的步骤 1.使用 private 来修饰成员变量。 2.使用 public 修饰getter和setter方法。 1.3.2 封装的步骤实现 private修饰成员变量 public修饰getter和setter方法 1.4.1 构造方法的作用 在创建对象的时候,给成员变量进行初始化。 初始化即赋值的意

    2024年02月03日
    浏览(13)
  • 从public static void main(String[] args)看如何构造数据

    java语言中public static void main(String[] args)里面的ages有什么作用? 在Java语言中, public static void main(String[] args) 是一个特殊的方法,它是Java程序的入口点。当你运行一个Java程序时,程序会从这个方法开始执行。这个方法的参数 String[] args 是一个字符串数组,用于传递命令行参数

    2024年02月12日
    浏览(8)
  • Mockito框架下如何优雅的验证调用Mock对象方法的入参

    该文章已同步至个人微信公众号[不能止步],欢迎关注。 在单元测试场景中,一种典型的场景是为了测试某一个类(Component Under Test, 简称CUT)而需要mock其依赖的的类。示例如下: 为了验证CUT业务实现的正确性,通常需要验证传给调用Mock对象的方法的参数的正确性。如果采

    2024年02月09日
    浏览(22)
  • C++类对象单元测试中的Mock使用

      在进行单元测试时,我们想要测试自己缩写 函数A ,但是 函数A 却依赖于 函数B ,当 函数B 无法满足预期时就无法对 函数A 进行测试,主要由于下面几个原因: 函数B 依赖于硬件设备 真实的 函数B 的返回值无法满足我们的预期 团队开发中 函数B 尚未实现   这时就需要

    2023年04月15日
    浏览(10)
  • java的面向对象编程(oop)——static概述及初始单例设计模式

    java的面向对象编程(oop)——static概述及初始单例设计模式

    过了入门阶段,开始学习进阶语法了。每天进步一点点,打好基础,daydayup! 什么是面向对象编程(oop),可以看这篇 java的面向对象编程(oop)概述及案例  static的意思为静态,用于修饰成员变量及成员方法。 成员变量根据有无static可以分为两种 ——类变量及实例变量 1,类

    2024年01月19日
    浏览(17)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包