如何使用PowerMock帮助做TDD?
2017-03-24 01:21
519 查看
在我们的日常工作,我们可能会在一些大型的遗留系统上重构或者新添加一些功能;为了不让代码变酸臭,我们会不停的对遗留的代码做重构,对新写的代码使用TDD(测试驱动 开发);但是对于一些大型的,旧的掉渣的系统,其里面包含了各种各样的方法,有静态的,有私有的,有final修饰的,这些方法往往会被很多其他的方法引用到,特别是静态的方法,简直就是全局作用域;或者对于一些被测试的类,其里面包含了一些私有方法或者用final修饰的方法,咱们压根不可能通过集成其类来覆写他们。这个时候我们概怎么办?幸好有PowerMock这个框架。
首先把其Maven的依赖分享出来,然后在一个个的例子来演示,PowerMock的最新版本是1.6.6;所以下面的powermock.version的值是1.6.6,且PowerMock是基于Mockito封装的(也可以基于EasyMock封装,本例子演示的都是基于Mockito封装的。)
<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-module-testng</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>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies>
/**
* @return A new ID based on the current time.
*/
public static long generateNewId() {
return System.currentTimeMillis();
}
}
测试方法:
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
/**
* An example on how to mock the call to a static method.
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(IdGenerator.class)
public class ServiceRegistratorTest {
@Test
public void registersServiceToRepository() throws Exception {
long expectedId = 42;
ServiceRegistartor tested = new ServiceRegistartor();
mockStatic(IdGenerator.class);
when(IdGenerator.generateNewId()).thenReturn(expectedId);
long actualId = tested.registerService(new Object());
verify(IdGenerator.class);
assertThat(actualId, is(expectedId));
}
}
注意,在测试方法的上面一定要加上@RunWith(PowerMockRunner.class),@PrepareForTest(IdGenerator.class) 否则会运行失败。
public final void finalAweSomePay(){
}
public static String getCompany(){
return CompanyService.getCurrentCompany();
}
private static String getCurrentCompany(){
return "Objectiva";
}
}
测试方法import org.junit.Test;
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(CompanyService.class)
public class CompanyServiceTest {
@Test
public void testGetCompany() {
//PowerMockito.mockStatic(CompanyService.class);
try {
PowerMockito.spy(CompanyService.class); //We must add this line,otherwise, the below will invoke the mock method
//PowerMockito.doReturn("IBM").when(CompanyService.class, "getCurrentCompany"); // Mock私有方法
PowerMockito.when(CompanyService.class, "getCurrentCompany").thenReturn("IBM");
System.out.println(CompanyService.getCompany());
assertEquals(CompanyService.getCompany(),"IBM");
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试类
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertEquals;
/**
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(FinalClass.class)
public class FinalClassTest {
@Test
public void testSayHello() {
FinalClass finalClass=PowerMockito.mock(FinalClass.class);
final String value = "What's up?";
Mockito.when(finalClass.sayHello()).thenReturn(value);
MyBean myBean=new MyBean(finalClass);
assertEquals(myBean.sayHello(),value);
Mockito.verify(finalClass, Mockito.times(1)).sayHello();
}
}
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(CarFactory.class)
public class CarFactoryTest {
private static final String TESTING_TYPE = "Tatra";
private static final String TESTING_COLOR = "Black";
@Test
public void testConstruct() throws Exception{
Car expectedCar = Mockito.mock(Car.class);
PowerMockito.whenNew(Car.class).withArguments(TESTING_TYPE, TESTING_COLOR).thenReturn(expectedCar);
CarFactory carFactory = new CarFactory();
Car actualCar = carFactory.constructCar(TESTING_TYPE, TESTING_COLOR);
Assert.assertEquals(actualCar, expectedCar);
PowerMockito.verifyNew(Car.class, Mockito.times(2)).withArguments(TESTING_TYPE, TESTING_COLOR);
}
}
注意:@PrepareForTest(CarFactory.class)里必须是CarFactory.class类,而不是Car.class类。
首先把其Maven的依赖分享出来,然后在一个个的例子来演示,PowerMock的最新版本是1.6.6;所以下面的powermock.version的值是1.6.6,且PowerMock是基于Mockito封装的(也可以基于EasyMock封装,本例子演示的都是基于Mockito封装的。)
<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-module-testng</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>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies>
@ 静态方法(Static)
public class IdGenerator {/**
* @return A new ID based on the current time.
*/
public static long generateNewId() {
return System.currentTimeMillis();
}
}
import java.util.HashMap; import java.util.Map; public class ServiceRegistartor { private Map<Long,Object> serviceRegistrations=new HashMap<Long,Object>(); public long registerService(Object service) { final long id = IdGenerator.generateNewId(); serviceRegistrations.put(id, service); return id; } }
测试方法:
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
/**
* An example on how to mock the call to a static method.
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(IdGenerator.class)
public class ServiceRegistratorTest {
@Test
public void registersServiceToRepository() throws Exception {
long expectedId = 42;
ServiceRegistartor tested = new ServiceRegistartor();
mockStatic(IdGenerator.class);
when(IdGenerator.generateNewId()).thenReturn(expectedId);
long actualId = tested.registerService(new Object());
verify(IdGenerator.class);
assertThat(actualId, is(expectedId));
}
}
注意,在测试方法的上面一定要加上@RunWith(PowerMockRunner.class),@PrepareForTest(IdGenerator.class) 否则会运行失败。
@ 私有方法(Private)
public class CompanyService {public final void finalAweSomePay(){
}
public static String getCompany(){
return CompanyService.getCurrentCompany();
}
private static String getCurrentCompany(){
return "Objectiva";
}
}
测试方法import org.junit.Test;
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(CompanyService.class)
public class CompanyServiceTest {
@Test
public void testGetCompany() {
//PowerMockito.mockStatic(CompanyService.class);
try {
PowerMockito.spy(CompanyService.class); //We must add this line,otherwise, the below will invoke the mock method
//PowerMockito.doReturn("IBM").when(CompanyService.class, "getCurrentCompany"); // Mock私有方法
PowerMockito.when(CompanyService.class, "getCurrentCompany").thenReturn("IBM");
System.out.println(CompanyService.getCompany());
assertEquals(CompanyService.getCompany(),"IBM");
} catch (Exception e) {
e.printStackTrace();
}
}
}
@ final类或者方法(final)
public class MyBean { FinalClass finalClass=null; public MyBean(FinalClass finalClass){ this.finalClass=finalClass; } public String sayHello(){ return finalClass.sayHello(); } }
public final class FinalClass { public final String sayHello(){ return "Hello, man!"; } }
测试类
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertEquals;
/**
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(FinalClass.class)
public class FinalClassTest {
@Test
public void testSayHello() {
FinalClass finalClass=PowerMockito.mock(FinalClass.class);
final String value = "What's up?";
Mockito.when(finalClass.sayHello()).thenReturn(value);
MyBean myBean=new MyBean(finalClass);
assertEquals(myBean.sayHello(),value);
Mockito.verify(finalClass, Mockito.times(1)).sayHello();
}
}
@ 构造函数或者依赖的新类(Constructor)
/** * Class to demonstrate how to make constructor testable by Mockito */ public class CarFactory { /** * Tiny method that wraps constructor. Is partially mocked by test. * * @param type * type of the car * @param color * color of the car * @return created car */ Car carFactoryMethod(String type, String color) { return new Car(type, color); } /** * Method to demonstrate how to make constructor testable by Mockito * * @param type * type of the car * @param color * color of the car * @return created instance by constructor */ public Car constructCar(String type, String color) { carFactoryMethod(type, color); return carFactoryMethod(type, color); } }
/** * Used to demonstrate mocking of constructor */ public class Car { /** * Used for constructor mocking demostration * * @param type * type of the car * @param color * color of the car */ public Car(String type, String color) { throw new UnsupportedOperationException("Fail if not mocked! [type=" + type + ", color=" + color + "]"); } }测试类
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(CarFactory.class)
public class CarFactoryTest {
private static final String TESTING_TYPE = "Tatra";
private static final String TESTING_COLOR = "Black";
@Test
public void testConstruct() throws Exception{
Car expectedCar = Mockito.mock(Car.class);
PowerMockito.whenNew(Car.class).withArguments(TESTING_TYPE, TESTING_COLOR).thenReturn(expectedCar);
CarFactory carFactory = new CarFactory();
Car actualCar = carFactory.constructCar(TESTING_TYPE, TESTING_COLOR);
Assert.assertEquals(actualCar, expectedCar);
PowerMockito.verifyNew(Car.class, Mockito.times(2)).withArguments(TESTING_TYPE, TESTING_COLOR);
}
}
注意:@PrepareForTest(CarFactory.class)里必须是CarFactory.class类,而不是Car.class类。
@参考资料:
https://github.com/powermock https://github.com/powermock/powermock.github.io https://blog.jayway.com/2013/03/05/beyond-mocking-with-powermock/ https://github.com/powermock/powermock/wiki/GettingStarted https://github.com/powermock/powermock/wiki/MockitoUsage https://github.com/lkrnac/blog-2014-01-unusual-mocking相关文章推荐
- 如何制作和使用帮助文件
- C++Builder 2007系列1-如何使用TDD For C/C++
- 在Windows7下如何使用以前版本的帮助文件(hlp文件)
- 11.5 如何使用路径帮助类(PathHelper)?
- 如何使用引导来帮助用户快速熟悉产品?
- 请求帮助:如何解决烦人的VS.NET2003编译时“无法将程序集复制到文件,另一个程序正在使用,进程无法访问”的问题?
- 如何使用 Core Plot 的 API 帮助文档
- INFO:使用InstallShield过程中,软件异常退出或崩溃时如何寻求帮助
- 请求帮助。 如何使用(c#)asp.net编写域名查询功能?
- 如何使用jxl 和 primface 下载excel文件 ,希望能帮助遇到同样问题的博主
- 我看了这些明白了如何使用正则表达式,希望对你也有帮助
- C++Builder 2007系列1-如何使用TDD For C/C++
- C++Builder 2007系列1-如何使用TDD For C/C++
- ABAP–如何在’REUSE_ALV_GRID_DISPLAY’使用自定义F4帮助,返回多个字段以及计算修改其他字段
- 如何使用专用管理连接进行问题诊断和处理 【摘自SQL Server在线帮助】
- 无法转向JDK 5.0?学习一款开放源代码工具如何帮助在旧版 JVM 上使用这些特性
- vs2005的帮助文档msdn使用方法/如何更好的使用MSDN!
- 教你如何使用EXCEL中的lookup函数(摘自“MS帮助和支持”)
- wireshark的使用教程--用实践的方式帮助我们理解TCP/IP中的各个协议是如何工作的
- WdatePicker.js的使用方法 帮助文档 使用说明 如何使用