`
ixp
  • 浏览: 12550 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

EasyMock gets more power with PowerMock.

阅读更多
There are a lot of mocking libraries for Java, out of which EasyMock is my favorite. It has been serving well for me until I had to unit test legacy code which did not completely adhere to IOC (inversion of control) principles and had a lot of static method calls and direct creation of service/helper objects instead of using dependency injection. Unfortunately EasyMock could not handle mocking of static methods and objects which were created directly in the class or method being tested along with some other limitations such handling final classes.
This forced me to use other mocking libraries until I encountered PowerMock. It provides all the ammunition (and more) in dealing with these issues and has nice integration with EasyMock.
Here I’ll show you how to use EasyMock with PowerMock in order to handle common mocking test cases which were not possible with EasyMock before.


Set Up.
First to use PowerMock with easymock you need PowerMock libraries.
Here is maven dependency list:
<dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>1.4.10</version>
        <scope>test</scope>
</dependency>
<dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-test-easymock-junit4</artifactId>
        <version>1.4.10</version>
        <scope>test</scope>
</dependency>
<dependency>
        <groupId>org.easymock</groupId>
        <artifactId>easymock</artifactId>
        <version>3.0</version>
        <scope>test</scope>
</dependency>

Code to be tested.
public class SampleService {

  private SampleServiceHelper sampleServiceHelper = new SampleServiceHelper();

  public String method1(){		
    return "method1:" + 
    SampleUtils.staticMethod(); 
   //we will need to mock this static method call
  }

  public String method2(){		
    return "method2:" + 
    sampleServiceHelper.helperMethod(); 
   //we will need to mock this method call on global variable that is created during class initialization
  }

  public String method3(){
    SampleServiceHelper2 sampleServiceHelper2 = new SampleServiceHelper2();
    return "method3:" + 
    sampleServiceHelper2.helperMethod();
   //we will need to mock this method call on variable that is created within this method
  }

  public String method4(){
    return "method4:" + 
    privateMethod("someParam");
    //we will partially mock this private method call
  }

  public String method5(){
    return "method5:" + 
    SampleUtils.staticMethod() + 
    privateMethod("someParam") +
    sampleServiceHelper.helperMethod();
    //we will mock all three calls in the last test
  }

  protected String privateMethod(String param){
    return "privateMethod-" + param;
  }
}
view rawSampleService.javaThis Gist brought to you by GitHub.
public final class SampleServiceHelper {

  public String helperMethod(){
    return "helperMethod";
  }
}
view rawSampleServiceHelper.javaThis Gist brought to you by GitHub.
public class SampleServiceHelper2 {

  public String helperMethod(){
    return "helperMethod";
  }
}
view rawSampleServiceHelper2.javaThis Gist brought to you by GitHub.
public class SampleUtils {

  private SampleUtils(){
  }

  public static String staticMethod(){
    return "staticMethod";
  }
}

view rawSampleUtils.javaThis Gist brought to you by GitHub.
The Unit Tests.
I am creating 5 different tests in order to gradually show you how to test different scenarios with last one combining all into one test as an example of how everything can work together.
import org.easymock.EasyMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;

import org.powermock.api.easymock.PowerMock;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.core.classloader.annotations.PrepareForTest;

//This is required for PowerMock to work.
@RunWith(PowerMockRunner.class)
//The following class are included in @PrepareForTest because:
//- SampleUtils.class. So that PowerMock will handle static method calls.
//  Notice that even though SampleUtils has private constructor PowerMock can 
//  still handle mocking it.  
//
//- SampleServiceHelper. Because its declared as final class and EasyMock wont 
//  be able to mock it.
//
//- SampleService.class. So that PowerMock could intercept creation
//  of SampleServiceHelper class. And could do partial mocking of 
//  "privateMethod" private method.
@PrepareForTest( {SampleUtils.class, SampleServiceHelper.class, 
SampleService.class} )
public class SampleServiceTest {

  @Test
  public void testMethod1() throws Exception{
    //This will mock the SampleUtils static method calls.
    PowerMock.mockStatic(SampleUtils.class);

    //Just do plain "new" of SampleService here since we are not calling
    //any private method inthis test method that need to be partially mocked.
    SampleService sampleService = new SampleService();

    //Here we are telling what should happens when SampleUtils.staticMethod()
    //gets called. We can use EasyMock to do the expectation even though PowerMock
    //is mocking the static method call.
    EasyMock.expect( SampleUtils.staticMethod() ).andReturn("mockedStaticMethod");

    //We need to have PowerMock replay SampleUtils.just like its done 
    //with SampleServiceHelper.class
    //We cannot use EasyMock in this case since it does not handle Class objects.
    PowerMock.replay(SampleUtils.class);

    //------ Do actually call the method to be tested and do necessary assertions.
    String result = sampleService.method1();

    assertEquals( "method1:" + "mockedStaticMethod", result );

    //------ Do necessary verification to make sure that all methods we expected
    //to be called are called

    //Verification of Class mocks need to go through PowerMock, just like in replay.
    PowerMock.verify(SampleUtils.class);	
  }

  @Test
  public void testMethod2() throws Exception{				
    //Here are going to tell PowerMock to replace all calls to new SampleServiceHelper
    //in SampleService with sampleServiceHelperMock. Notice that even though SampleServiceHelper is final
    //we now can mock it using EasyMock because is included in @PrepareForTest declaration.
    //Powermock example says to use PowerMock.mock but this works as well.
    SampleServiceHelper sampleServiceHelperMock = 
    EasyMock.createMock(SampleServiceHelper.class);		
    //Here we tell PowerMock to intercept all creations of SampleServiceHelper
    PowerMock.expectNew(SampleServiceHelper.class).andReturn(sampleServiceHelperMock);					
    //PowerMock requires us to call this. Otherwise it will fail to intercept call to 
    //"new" SampleServiceHelper. Cant use EasyMock here since it does not support
    //mocking Class objects.
    PowerMock.replay(SampleServiceHelper.class);

    //We need to create SampleService after the above call because
    //SampleServiceHelper is created during SampleService initialization.
    //"method3" will show you that you dont need to do this when object to be mocked
    //is created inside method that is tested.
    //
    //Just do plain "new" of SampleService here since we are not calling any method in
    //this test method that need to be partially mocked.
    SampleService sampleService = new SampleService();

    //We can use EasyMock to replay plain mocks. 
    EasyMock.expect( sampleServiceHelperMock.helperMethod() )
    .andReturn("mockedHelperMethod");

    //Again since sampleServiceHelper is mocked with EasyMock, we can replay it with
    //EasyMock.
    EasyMock.replay(sampleServiceHelperMock);

    //------ Do actually call the method to be tested and do necessary assertions.
    String result = sampleService.method2();

    assertEquals( "method2:" + "mockedHelperMethod", result );

    //------ Do necessary verification to make sure that all methods we expected
    //to be called are called

    //Verification of Class mocks need to go through PowerMock, just like in replay.
    PowerMock.verify(SampleServiceHelper.class);	
  
    EasyMock.verify(sampleServiceHelperMock);
  }

  @Test
  public void testMethod3() throws Exception{				
    //Here are going to tell PowerMock to replace call to new SampleServiceHelper2
    //in SampleService with sampleServiceHelper2Mock.
    SampleServiceHelper2 sampleServiceHelper2Mock = 
    EasyMock.createMock(SampleServiceHelper2.class);		
    //Here we tell PowerMock to intercept all creations of SampleServiceHelper2
    PowerMock.expectNew(SampleServiceHelper2.class).andReturn(sampleServiceHelper2Mock);					

    //Here we dont need to create SampleService before calling 
    //PowerMock.replay(SampleServiceHelper2.class), since SampleServiceHelper2
    //is created inside method3.
    //
    //Just do plain "new" of SampleService here since we are not calling any method in
    //this test method that need to be partially mocked.
    SampleService sampleService = new SampleService();
  
    //Called after creation of SampleService.
    PowerMock.replay(SampleServiceHelper2.class);

    //We can use EasyMock to replay plain mocks. 
    EasyMock.expect( sampleServiceHelper2Mock.helperMethod() )
    .andReturn("mockedHelperMethod");

    //Again since sampleServiceHelper2Mock is mocked with EasyMock and we can replay it with
    //EasyMock. Notice that even though "sampleService" is partially mocked by PowerMock
    //we still can replay it using EasyMock.
    EasyMock.replay(sampleServiceHelper2Mock);

    //------ Do actually call the method to be tested and do necessary assertions.
    String result = sampleService.method3();

    assertEquals( "method3:" + "mockedHelperMethod", result );

    //------ Do necessary verification to make sure that all methods we expected
    //to be called are called

    //Verification of Class mocks need to go through PowerMock, just like in replay.
    PowerMock.verify(SampleServiceHelper2.class);	

    EasyMock.verify(sampleServiceHelper2Mock);
  }

  @Test
  public void testMethod4() throws Exception{		
    //Since we want to mock "privateMethod" we need to
    //partially mock SampleService with PowerMock. 
    //
    //Also notice that we are not calling createPartialMock with constructor
    //arguments (like in testMethod5) since method4 does not use SampleServiceHelper.
    SampleService sampleService = 
    PowerMock.createPartialMock(SampleService.class, 
    "privateMethod", new Class[]{String.class} );

    PowerMock.expectPrivate(sampleService, "privateMethod",
    "someParam").andReturn("mockedPrivateMethod");

    //Notice that even though "sampleService" is partially mocked by PowerMock
    //we still can replay it using EasyMock.
    EasyMock.replay(sampleService);

    //------ Do actually call the method to be tested and do necessary assertions.
    String result = sampleService.method4();

    assertEquals( "method4:" + "mockedPrivateMethod", result );

    //------ Do necessary verification to make sure that all methods we expected
    //to be called are called

    EasyMock.verify(sampleService);
  }

  @Test
  public void testMethod5() throws Exception{
    //This will mock the SampleUtils static method calls.
    PowerMock.mockStatic(SampleUtils.class);

    //Here are going to tell PowerMock to replace calls to new SampleServiceHelper
    //in SampleService with sampleServiceHelperMock.
    SampleServiceHelper sampleServiceHelperMock = 
    EasyMock.createMock(SampleServiceHelper.class);		
    //Here we tell PowerMock to intercept all creations of SampleServiceHelper
    PowerMock.expectNew(SampleServiceHelper.class).andReturn(sampleServiceHelperMock);					
    //PowerMock requires us to call this. Otherwise it will fail to intercept call to 
    //"new" SampleServiceHelper. Cant use EasyMock here since it does not support
    //mocking Class objects.
    PowerMock.replay(SampleServiceHelper.class);

    //We need to create SampleService after the above call because
    //SampleServiceHelper is create during SampleService initialization
    //"method3" will show you that you dont need to do this when object to be mocked
    //is created inside method that is tested.
    //
    //Since we want to mock "privateMethod" (which is private) we need to
    //partially mock SampleService with PowerMock. 
    //
    //Also notice that we are calling createPartialMock with constructor
    //arguments since plain createPartialMock wont "by default" invoke constructor and
    //do class initialization which will prevent us from initializing sampleServiceHelper
    //variable.
    SampleService sampleService = 
    PowerMock.createPartialMock(SampleService.class, 
    "privateMethod", new Class[]{String.class}, new Object[]{}, new Class[]{} );

    PowerMock.expectPrivate(sampleService, "privateMethod",
    "someParam").andReturn("mockedPrivateMethod");
        		
    //Here we are telling what should happens when SampleUtils.staticMethod()
    //gets called. We can use EasyMock to do the expectation even though PowerMock
    //is mocking the static method call.
    EasyMock.expect( SampleUtils.staticMethod() ).andReturn("mockedStaticMethod");

    //We need to have PowerMock replay SampleUtils.just like its done 
    //with SampleServiceHelper.class
    PowerMock.replay(SampleUtils.class);

    //We can use EasyMock to replay plain mocks. 
    EasyMock.expect( sampleServiceHelperMock.helperMethod() )
    .andReturn("mockedHelperMethod");

    //Again since sampleServiceHelper is mocked with EasyMock, we can replay it with
    //EasyMock. Notice that even though "sampleService" is partially mocked by PowerMock
    //we still can replay it using EasyMock.
    EasyMock.replay(sampleServiceHelperMock, sampleService);

    //------ Do actually call the method to be tested and do necessary assertions.
    String result = sampleService.method5();

    assertEquals( "method5:" + "mockedStaticMethod" + 
    "mockedPrivateMethod" + "mockedHelperMethod", result );

    //------ Do necessary verification to make sure that all methods we expected
    //to be called are called
    
    //Verification of Class mocks need to go through PowerMock, just like in replay.
    PowerMock.verify(SampleUtils.class, SampleServiceHelper.class);	

    EasyMock.verify(sampleServiceHelperMock, sampleService);
  }
}

view rawSampleServiceTest.javaThis Gist brought to you by GitHub.
Update: Just encountered limitation with PowerMock (and probably with any other Mocking frameworks) that it cannot mock “java.lang.reflect.Method”. The workaround is to just declare inner class that has method you need to mock.
分享到:
评论

相关推荐

    easymock3.1 jar包和powermock1.4.10 jar包(以及附带junit jar包)

    在单元测试领域,Easymock和PowerMock是两个非常重要的工具,它们允许开发者模拟复杂的对象行为以便于测试。这两个库都是JUnit框架的扩展,帮助我们编写更清晰、更易于维护的测试代码。 Easymock3.1是Easymock的一...

    单元测试模拟框架PowerMock.zip

    PowerMock 也是一个单元测试模拟...PowerMock 的目的就是在当前已经被大家所熟悉的接口上通过添加极少的方法和注释来实现额外的功能,目前,PowerMock 仅支持 EasyMock 和 Mockito。 标签:PowerMock 单元测试

    easymock2-2.5.2-12.el7.noarch.rpm

    离线安装包,亲测可用

    easymock3.1最新帮助文档chm格式

    easymock3.1最新帮助文档chm格式

    powermock-easymock-junit-1.5.4.zip

    PowerMock与EasyMock是Java单元测试领域中的两个重要库,它们与JUnit结合使用,能够帮助开发者在测试过程中模拟复杂的对象行为和系统环境。这个压缩包"powermock-easymock-junit-1.5.4.zip"很可能包含了这三个库的...

    EasyMock 使用方法与原理剖析.rar

    - **Strict Mocks**:如果希望模拟对象对每个未预设的方法调用都抛出异常,可以使用`EasyMock.createStrictMock()`。 - **Partial Mocks**:部分模拟允许在一个真实的对象上只模拟部分方法,其他方法则保持原样。 ...

    powermock-easymock-junit-1.6.1.zip

    在Java单元测试中,PowerMock和EasyMock是两个强大的库,它们扩展了JUnit的功能,使得开发者可以测试那些通常难以或无法直接测试的代码。PowerMock是基于EasyMock的一个扩展,它允许模拟静态方法、构造函数、final类...

    PowerMock.zip

    PowerMock 是一个强大的Java单元测试框架的扩展,它允许开发者模拟静态方法、构造函数、final 类、enum 和私有方法,这些都是传统单元测试工具如JUnit和EasyMock无法处理的。这个压缩包“PowerMock.zip”可能包含...

    powermock依赖jar文件.rar

    PowerMock是一个扩展了其他Mock框架(如EasyMock)的库,它通过使用字节码操作库(如ByteBuddy或ASM)来实现对静态方法、构造器、final类和方法以及静态初始化块的模拟。这使得我们可以在测试中控制这些通常被认为是...

    easymock.jar,easymockclassextension.jar

    在给定的压缩包文件中,包含两个核心的JAR文件:`easymock.jar`和`easymockclassextension.jar`。 `easymock.jar`是Easymock的基本库,包含了框架的主要功能。它提供了模拟接口和类的方法,以及验证这些方法是否被...

    easymockclassextension-3.0.jar

    easymockclassextension-3.0.jar org.easymock.classextension.EasyMock.

    com.springsource.org.easymock.classextension-2.3.0.jar

    jar包,官方版本,自测可用

    easymock-1.2_java1.5.jar

    jar包,官方版本,自测可用

    EasyMock and PowerMock入门PPT

    - 下载EasyMock.jar(版本2.0以后需要Java 5.0及以上)。 - 如果需要模拟抽象类,还需要easymockclassextension.jar。 - JUnit.jar(版本3.8.1以上)用于运行测试用例。 **EasyMock的基本使用步骤** 1. 使用`...

    rh-java-common-easymock3-3.3-1.5.el7.noarch.rpm

    官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装

    rh-java-common-easymock2-2.5.2-12.15.el7.noarch.rpm

    官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装

    PowerMock\EasyMock的相关资料和文档

    PowerMock和EasyMock是Java单元测试领域中的两个重要工具,它们允许开发者模拟和控制对象的行为,以便在测试中隔离复杂的依赖关系。EasyMock是基础,而PowerMock则在其基础上扩展了更多的功能,使得一些难以模拟的...

    easymockclassextension-2.4.jar

    easymockclassextension-2.4.jar是一个很齐全的jar包,可以放心下载使用

    easymock-3.2.jar

    EasyMock主要是为测试提供模拟数据,比如你可以模拟HttpServletRequest。

    easymock2.4+EasyMock使用简明手册.pdf

    4. **启动回放**:调用`EasyMock.replay()`开始回放模式,模拟对象开始按照之前设置的期望进行。 5. **执行测试**:在测试代码中使用模拟对象,执行测试场景。 6. **验证**:测试结束后,调用`EasyMock.verify()`...

Global site tag (gtag.js) - Google Analytics