您的位置:首页 > 其它

如何使用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>

@ 静态方法(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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  PowerMock TDD
相关文章推荐