如何使用PowerMock帮助做TDD?

原创 2017年03月24日 01:21:05

在我们的日常工作,我们可能会在一些大型的遗留系统上重构或者新添加一些功能;为了不让代码变酸臭,我们会不停的对遗留的代码做重构,对新写的代码使用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 入门介绍及使用示例

转自:http://blog.csdn.net/rainbow702/article/details/51783285 相关框架 JUnit4、Mockit、Power...

Java单元测试之模拟利器-使用PowerMock进行Mock测试

原文:http://www.w2bc.com/article/111452 简介 mock是模拟对象,用于模拟真实对象的行为。 Powermock主要用于打桩。比如:方法A的参数需要传入...
  • xjj1314
  • xjj1314
  • 2016年11月23日 20:53
  • 1150

使用Powermock实现单元测试,提高单元测试覆盖率

1. PowerMock介绍(本章属于普及知识,熟悉这直接跳过)     软件设计开发过程中,通常采用分模块、并行开发的模式。在开发周期中,当前模块所依赖的其他模块只有接口,没有具体实现。为了实现对...
  • highth
  • highth
  • 2015年01月07日 18:07
  • 1560

【测试方法】使用PowerMock进行静态方法测试

简介一般来说,Java中的静态方法无法用传统的Jmock进行单测,这也就给研发人员和测试人员造成了一定的困扰。本文介绍一种使用PowerMock执行静态方法单元测试的手段,其实网上也有使用如Mocki...
  • hbmovie
  • hbmovie
  • 2017年07月21日 16:06
  • 60

使用powerMock和mockito模拟静态方法和私有方法

首先我们要导入相应的包 org.powermock powermock-api-mockito 1.4.12 test o...
  • ynwso
  • ynwso
  • 2014年02月17日 17:13
  • 16971

使用Powermock和mockito

使用powermock所需要的jar如下: maven:

单元测试及框架简介 --junit、jmock、mockito、powermock的简单使用

一、单元测试 单元测试概念: 所谓MT(MK23),又称为模块测试,是指对软件中的最小可测试单元进行检查和验证。对于面向对象编程,最小单元就是方法。单元测试的目标是隔离程序部件并证明这些单个部件是正确...

使用MRUnit,Mockito和PowerMock进行Hadoop MapReduce作业的单元测试

0、preliminary 环境搭建Setup development environmentDownload the latest version of MRUnit jar from Apache...

使用Powermock和mockito来进行单元测试

简介 Mockito是一个流行的Mocking框架。它使用起来简单,学习成本很低,而且具 有非常简洁的API,测试代码的可读性很高。因此它十分受欢迎,用户群越来越 多,很多的开源的软件也选择了M...

使用PowerMock和Easymock进行单元测试

Java单元测试对于开发人员质量保证至关重要,尤其当面对一团乱码的遗留代码时,没有高覆盖率的单元测试做保障,没人敢轻易对代码进行重构。然而单元测试的编写也不是一件容易的事情,除非使用TDD方式,否则编...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:如何使用PowerMock帮助做TDD?
举报原因:
原因补充:

(最多只允许输入30个字)