在我们的日常工作,我们可能会在一些大型的遗留系统上重构或者新添加一些功能;为了不让代码变酸臭,我们会不停的对遗留的代码做重构,对新写的代码使用TDD(测试驱动 开发);但是对于一些大型的,旧的掉渣的系统,其里面包含了各种各样的方法,有静态的,有私有的,有final修饰的,这些方法往往会被很多其他的方法引用到,特别是静态的方法,简直就是全局作用域;或者对于一些被测试的类,其里面包含了一些私有方法或者用final修饰的方法,咱们压根不可能通过集成其类来覆写他们。这个时候我们概怎么办?幸好有PowerMock这个框架。
首先把其Maven的依赖分享出来,然后在一个个的例子来演示,PowerMock的最新版本是1.6.6;所以下面的powermock.version的值是1.6.6,且PowerMock是基于Mockito封装的(也可以基于EasyMock封装,本例子演示的都是基于Mockito封装的。)
1.6.6
org.powermock
powermock-module-junit4
${powermock.version}
test
org.powermock
powermock-module-testng
${powermock.version}
test
org.powermock
powermock-api-mockito
${powermock.version}
test
junit
junit
4.11
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 serviceRegistrations=new HashMap();
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));
}
}
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();
}
}
}
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();
}
}
/**
* 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);
}
}
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