单元测试模拟框架的功能及其实现简介
Mockito 是一个针对 Java 的单元测试模拟框架,它与 EasyMock 和 jMock 很相似,都是为了简化单元测试过程中测试上下文 ( 或者称之为测试驱动函数以及桩函数 ) 的搭建而开发的工具。在有这些模拟框架之前,为了编写某一个函数的单元测试,程序员必须进行十分繁琐的初始化工作,以保证被测试函数中使用到的环境变量以 及其他模块的接口能返回预期的值,有些时候为了单元测试的可行性,甚至需要牺牲被测代码本身的结构。单元测试模拟框架则极大的简化了单元测试的编写过程: 在被测试代码需要调用某些接口的时候,直接模拟一个假的接口,并任意指定该接口的行为。这样就可以大大的提高单元测试的效率以及单元测试代码的可读性。
PowerMock 也是一个单元测试模拟框架,它是在其它单元测试模拟框架的基础上做出的扩展。通过提供定制的类加载器以及一些字节码篡改技巧的应用,PowerMock 现了对静态方法、构造方法、私有方法以及 Final 方法的模拟支持,对静态初始化过程的移除等强大的功能。因为 PowerMock 在扩展功能时完全采用和被扩展的框架相同的 API, 熟悉 PowerMock 所支持的模拟框架的开发者会发现 PowerMock 非常容易上手。PowerMock 的目的就是在当前已经被大家所熟悉的接口上通过添加极少的方法和注释来实现额外的功能,目前,PowerMock 仅支持 EasyMock 和 Mockito。
环境配置方法
对于需要的开发包,PowerMock 网站提供了”一站式”下载 : 从 此页面中选择以类似 PowerMock 1.4.10 with Mockito and JUnit including dependencies 为注释的链接,该包中包含了最新的 JUnit 库,Mockito 库,PowerMock 库以及相关的依赖。
如果是使用 Eclipse 开发,只需要在 Eclipse 工程中包含这些库文件即可。
如果是使用 Maven 开发,则需要根据版本添加以下清单内容到 POM 文件中:
JUnit 版本 4.4 以上请参考清单 1,
清单 1
<properties> <powermock.version>1.4.10</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>
JUnit 版本 4.0-4.3 请参考清单 2,
清单 2
<properties> <powermock.version>1.4.10</powermock.version> </properties> <dependencies> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4-legacy</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>
JUnit 版本 3 请参考清单 3,
清单 3
<properties> <powermock.version>1.4.10</powermock.version> </properties> <dependencies> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit3</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>
PowerMock 在单元测试中的应用
模拟 Static 方法
在任何需要用到 PowerMock 的类开始之前,首先我们要做如下声明:
@RunWith(PowerMockRunner.class)
然后,还需要用注释的形式将需要测试的静态方法提供给 PowerMock:
@PrepareForTest( { YourClassWithEgStaticMethod.class })
然后就可以开始写测试代码:
首先,需要有一个含有 static 方法的代码 , 如清单 4:
清单 4
public class IdGenerator { ... public static long generateNewId() { ... } ... }
然后,在被测代码中,引用了以上方法 , 如清单 5 所示:
清单 5
public class ClassUnderTest { ... public void methodToTest() { .. final long id = IdGenerator.generateNewId(); .. } ... }
为了达到单元测试的目的,需要让静态方法 generateNewId()
返回各种值来达到对被测试方法 methodToTest()
的覆盖测试,实现方式如清单 6 所示:
清单 6
@RunWith(PowerMockRunner.class) //We prepare the IdGenerator for test because the static method is normally not mockable @PrepareForTest(IdGenerator.class) public class MyTestClass { @Test public void demoStaticMethodMocking() throws Exception { mockStatic(IdGenerator.class); /* * Setup the expectation using the standard Mockito syntax, * generateNewId() will now return 2 everytime it's invoked * in this test. */ when(IdGenerator.generateNewId()).thenReturn(2L); new ClassUnderTest().methodToTest(); // Optionally verify that the static method was actually called verifyStatic(); IdGenerator.generateNewId(); } }
如清单 6 中所展示,在测试代码中,可以使用 When().thenReturn(
) 语句来指定被引用的静态方法返回任意需要的值,达到覆盖测试的效果。
模拟构造函数
有时候,能模拟构造函数,从而使被测代码中 new
操作返回的对象可以被随意定制,会很大程度的提高单元测试的效率,考虑如清单 7 的代码:
清单 7
public class DirectoryStructure { public boolean create(String directoryPath) { File directory = new File(directoryPath); if (directory.exists()) { throw new IllegalArgumentException( "\"" + directoryPath + "\" already exists."); } return directory.mkdirs(); } }
为了充分测试 create()
函数,我们需要被 new
出来的 File 对象返回文件存在和不存在两种结果。在 PowerMock 出现之前,实现这个单元测试的方式通常都会需要在实际的文件系统中去创建对应的路径以及文件。然而,在 PowerMock 的帮助下,本函数的测试可以和实际的文件系统彻底独立开来:使用 PowerMock 来模拟 File 类的构造函数,使其返回指定的模拟 File 对象而不是实际的 File 对象,然后只需要通过修改指定的模拟 File 对象的实现,即可实现对被测试代码的覆盖测试,参考如清单 8 的代码:
清单 8
@RunWith(PowerMockRunner.class) @PrepareForTest(DirectoryStructure.class) public class DirectoryStructureTest { @Test public void createDirectoryStructureWhenPathDoesntExist() throws Exception { final String directoryPath = "mocked path"; File directoryMock = mock(File.class); // This is how you tell PowerMockito to mock construction of a new File. whenNew(File.class).withArguments(directoryPath).thenReturn(directoryMock); // Standard expectations when(directoryMock.exists()).thenReturn(false); when(directoryMock.mkdirs()).thenReturn(true); assertTrue(new NewFileExample().createDirectoryStructure(directoryPath)); // Optionally verify that a new File was "created". verifyNew(File.class).withArguments(directoryPath); } }
使用 whenNew().withArguments().thenReturn()
语句即可实现对具体类的构造函数的模拟操作。然后对于之前创建的模拟对象 directoryMock
使用 When().thenReturn()
语句,即可实现需要的所有功能,从而实现对被测对象的覆盖测试。在本测试中,因为实际的模拟操作是在类 DirectoryStructureTest
中实现,所以需要指定的 @PrepareForTest
对象是 DirectoryStructureTest.class
。
模拟私有以及 Final 方法
为了实现对类的私有方法或者是 Final 方法的模拟操作,需要 PowerMock 提供的另外一项技术:局部模拟。
在之前的介绍的模拟操作中,我们总是去模拟一整个类或者对象,然后使用 When().thenReturn()
语句去指定其中值得关心的部分函数的返回值,从而达到搭建各种测试环境的目标。对于没有使用 When().thenReturn()
方法指定的函数,系统会返回各种类型的默认值(具体值可参考官方文档)。
局部模拟则提供了另外一种方式,在使用局部模拟时,被创建出来的模拟对象依然是原系统对象,虽然可以使用方法 When().thenReturn()
来指定某些具体方法的返回值,但是没有被用此函数修改过的函数依然按照系统原始类的方式来执行。
这种局部模拟的方式的强大之处在于,除开一般方法可以使用之外,Final 方法和私有方法一样可以使用。
参考如清单 9 所示的被测代码:
清单 9
public final class PrivatePartialMockingExample { public String methodToTest() { return methodToMock("input"); } private String methodToMock(String input) { return "REAL VALUE = " + input; } }
为了保持单元测试的纯洁性,在测试方法 methodToTest()
时,我们不希望受到私有函数 methodToMock()
实现的干扰,为了达到这个目的,我们使用刚提到的局部模拟方法来实现 , 实现方式如清单 10:
清单 10
@RunWith(PowerMockRunner.class) @PrepareForTest(PrivatePartialMockingExample.class) public class PrivatePartialMockingExampleTest { @Test public void demoPrivateMethodMocking() throws Exception { final String expected = "TEST VALUE"; final String nameOfMethodToMock = "methodToMock"; final String input = "input"; PrivatePartialMockingExample underTest = spy(new PrivatePartialMockingExample()); /* * Setup the expectation to the private method using the method name */ when(underTest, nameOfMethodToMock, input).thenReturn(expected); assertEquals(expected, underTest.methodToTest()); // Optionally verify that the private method was actually called verifyPrivate(underTest).invoke(nameOfMethodToMock, input); } }
可以发现,为了实现局部模拟操作,用来创建模拟对象的函数从 mock()
变成了 spy()
,操作对象也从类本身变成了一个具体的对象。同时,When()
函数也使用了不同的版本:在模拟私有方法或者是 Final 方法时,When()
函数需要依次指定模拟对象、被指定的函数名字以及针对该函数的输入参数列表。
相关推荐
标签:powermock、module、junit4、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准...
PowerMock与EasyMock是Java单元测试领域中的两个重要库,它们与JUnit结合使用,能够帮助开发者在测试过程中模拟复杂的对象行为和系统环境。这个压缩包"powermock-easymock-junit-1.5.4.zip"很可能包含了这三个库的...
标签:powermock、module、junit4、common、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和...
PowerMock和Mockito是两个非常流行的Java单元测试框架,结合JUnit,它们可以提供强大的测试能力。在本文中,我们将深入探讨"PowerMock+Mockito-junit测试套件1.6.3版本"中的关键概念、功能和使用方法。 **PowerMock...
PowerMock-Mockito-JUnit-1.6.2.zip 是一个包含PowerMock、Mockito和JUnit集成库的压缩包,适用于Java开发环境。这个版本的PowerMock要求使用1.6或更高版本的Java Development Kit (JDK)。下面将详细解释这三个主要...
在 Java 单元测试领域,EasyMock 和 JUnit 是两个常用库,PowerMock 就是与它们结合使用的,提供了更全面的模拟功能。 在传统的单元测试中,我们通常会遵循“测试隔离”原则,即测试代码只关注被测试对象的行为,而...
在Java单元测试中,PowerMock和EasyMock是两个强大的库,它们扩展了JUnit的功能,使得开发者可以测试那些通常难以或无法直接测试的代码。PowerMock是基于EasyMock的一个扩展,它允许模拟静态方法、构造函数、final类...
PowerMock-Mockito-JUnit-1.6.3.zip 是一个包含最新版本的 PowerMock、Mockito 和 JUnit 库的压缩文件。这些工具在Java开发中被广泛用于单元测试和模拟,尤其对于处理静态方法、构造器、final类和方法、私有方法等...
JUnit作为最常用的Java单元测试框架,极大地简化了测试工作。然而,对于某些难以测试的代码,如静态方法、私有方法或者依赖外部系统的情况,JUnit就显得力不从心。这时,PowerMock介入,为复杂的测试场景提供了强大...
PowerMock是一个强大的Java单元测试框架,它扩展了如Mockito这样的工具,允许开发者模拟静态方法、构造函数、final类和方法、私有方法以及删除静态初始化器。在Java开发中,有时我们需要对不可Mock的对象进行单元...
总结一下,Easymock3.1和PowerMock1.4.10是Java单元测试的重要工具,它们与JUnit配合使用,可以帮助开发者对各种复杂情况进行精确的测试,提高代码质量。在实际项目中,正确地使用这些库可以大大提升测试的覆盖率和...
java运行依赖jar包
java运行依赖jar包
PowerMock 是一个强大的Java单元测试框架的扩展,它允许开发者模拟静态方法、构造函数、final 类、enum 和私有方法,这些都是传统单元测试工具如JUnit和EasyMock无法处理的。这个压缩包“PowerMock.zip”可能包含...
《PowerMock实战手册》是一本专注于使用PowerMock进行单元测试的指南,结合了Junit测试框架和Mockito库,为开发者提供了全面的测试解决方案。在实际的软件开发中,单元测试是确保代码质量的重要环节,它能帮助我们找...
PowerMock是一个强大的Java单元测试框架,它可以扩展其他流行的测试框架,如JUnit和TestNG。它的核心功能之一就是能够模拟静态方法、构造函数、final类和方法、私有方法等,这些都是传统单元测试难以处理的部分。 ...
PowerMock是一个强大的Java单元测试框架,它允许测试代码中静态方法、私有方法以及final类的模拟。它通常与JUnit和EasyMock等测试框架结合使用,用于更高效的单元测试。 标题“PowerMock实战”意味着本书将深入介绍...
除了EasyMock和JUnit,还需要PowerMock的核心库和相关的类加载器,如`powermock-api-easymock`、`powermock-module-junit4`等。 **PowerMock的扩展功能** - 模拟静态方法和类。 - 模拟final类和方法。 - 删除静态...
它间接引用 junit-4.12 mockito-core-2.15.0 但是官网powermock 1.7.x只支持2.8.0-2.8.9,如果使用默认引入版本,会出现找不到某些方法的异常. 需要自定义mockito-core为相应版本。 ServiceAspect只是为了验证当spy...