`

easymock教程-partial class mocking

阅读更多

    easymock中提供对于类的mock功能,我们可以方便的mock这个类的某些方法,指定预期的行为以便测试这个类的调用者。这种场景下被mock的类在测试案例中扮演的是次要测试对象或者说依赖的角色,主要测试对象是这个mock类的调用者。但是有时候我们需要将这个测试类作为主要测试对象,我们希望这个类中的部分(通常是大部分)方法保持原有的正常行为,只有个别方法被我们mock掉以便测试。

 

1. 使用方法

 

    我们先来看看这个partial class mocking 是如何工作的:

    public class Service {

        
public void execute() {
            actualMethod();
            needMockMethod();
        }


        
void actualMethod() {
            System.out.println(
"call actualMethod()");
        }


        
public void needMockMethod() {
            System.out.println(
"call needMockMethod()");
        }


    }

    我们给出了一个非常简单的类,我们将要测试execute()方法,期望能测试到actualMethod()这个方法的正常行为,然后需要mock掉needMockMethod().

public class PartialClassMockTest extends Assert {

    @Test
    
public void testPartialMock() {
        Service service 
= EasyMock.createMockBuilder(Service.class).addMockedMethod("needMockMethod").createMock();
        service.needMockMethod();
        EasyMock.expectLastCall();

        EasyMock.replay(service);
        service.execute();
        EasyMock.verify(service);
    }

}

    上面的测试案例运行通过,输出为"call actualMethod()",没有"call needMockMethod()",说明我们设置的mock生效了。我们创建的mock类的确是只有部分我们制定的方法是mock的,其他都是正常行为。

 

    再来看看为什么我们要需要partial class mocking 这个功能?为什么需要mock掉其中的一个方法?

 

    我们来看看下面这个更加真实的例子:

   public class Service {

        
public String execute2() {
            
return getConfiguration();
        }


        
public String getConfiguration() {
            
return Configuration.getUsername();
        }

    }


    
public class Configuration {
        
public static String getUsername() {
            
//ignore the code to get configuration from file or database
            return "username";
        }

    }

    这里例子中,需要测试的 execute2()方法需要调用getConfiguration()方法,而getConfiguration()方法则调用了Configuration的静态方法来获取配置信息。我们假设读取配置的代码比较复杂不能直接在单元测试环境下运行,因此通过情况下这里的execute2()方法就会因为这个getConfiguration()而造成无法测试。因此我们可以考虑通过partial class mocking的功能来mock掉getConfiguration()方法从而使得我们的测试案例可以覆盖到execute2()方法

 

    @Test
    
public void testStaticMethod() {
        Service service 
= EasyMock.createMockBuilder(Service.class).addMockedMethod("getConfiguration").createMock();
        EasyMock.expect(service.getConfiguration()).andReturn(
"abc");

        EasyMock.replay(service);
        assertEquals(
"abc", service.execute2());
        EasyMock.verify(service);
    }

    这个测试案例可以正常通过,我们通过partial class mocking成功的避开了getConfiguration()这个绊脚石。

 

    当然这里的实例代码本身就有点问题,应该采用DI的方法将configuration注入进来,而不是在内部通过静态方法来获取。因此一个建议是在使用partial class mocking功能前,先看看是不是可以通过重构来显改进测试类。只有当我们有足够充分的不得已的理由时,才使用partial class mocking这种变通(或者说取巧)的方式来解决问题。

   
2. 限制

 

    上面两个例子中,我们仔细看看会发现,被mock的方法都是public的。我们试着将方法修改为protected和default,partial class mocking依然生效。但是修改为private之后,则抛出异常:

 

java.lang.IllegalArgumentException: Method not found (or private): needMockMethod
 at org.easymock.internal.MockBuilder.addMockedMethod(MockBuilder.java:75)
 at net.sourcesky.study.easymock.tutorial.PartialClassMockTest.testPartialMock(PartialClassMockTest.java:52)

 

    或者将mock的方法继续保持public,但是加上final,则抛出以下异常:

 

java.lang.IllegalStateException: no last call on a mock available
 at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:521)
 at org.easymock.EasyMock.expectLastCall(EasyMock.java:512)
 at net.sourcesky.study.easymock.tutorial.PartialClassMockTest.testPartialMock(PartialClassMockTest.java:54)

 

    我们回到之前的章节,class mocking里面讲述了class mocking的一些限制:private方法和final方法是不能mock的。partial class mocking下这些限制依然存在。因此,为了开启partial class mocking,我们不得不稍微破坏一下类的封装原则,对于原本应该是private的方法,修改为protected或者default。

    不得不再次申明,partial class mocking不是一个足够好的解决方案,它只适合在不得已的情况下使用,不要太依赖这个特性。重构代码改善代码才是王道。

3. 疑问

    另外class mocking中还讲到,对于类的equals(), toString()和hashCode()这三个方法,class mocking下是easymock为这三个方法内建了easymock的实现,因此也不能mock。而partial class mocking,这三个方法同样不能mock,但是easymock不再为它们内建实现,而是使用它们正常的功能。

 

    关于这点还是有一点疑问,我在easymock的官方文档中看到以下描述

Remark: EasyMock provides a default behavior for Object's methods (equals, hashCode, toString). However, for a partial mock, if these methods are not mocked explicitly, they will have their normal behavior instead of EasyMock default's one.

 

    言下之意,似乎equals, hashCode, toString这三个方法还是可以显式mock的。但是我测试了一下:

    public class Service {

        
public String execute3() {
            actualMethod();
            
return toString();
        }


        @Override
        
public String toString() {
            
return "defaultToString()";
        }

    }


    @Test
    
public void testToStringMethod() {
        Service service 
= EasyMock.createMockBuilder(Service.class).addMockedMethod("toString").createMock();
        EasyMock.expect(service.toString()).andReturn(
"abc");
        EasyMock.replay(service);
        assertEquals(
"abc", service.execute3());
        EasyMock.verify(service);
    }

    toString()方法的mock没能生效,抛出异常:

 

java.lang.IllegalStateException: no last call on a mock available
 at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:521)
 at org.easymock.EasyMock.expect(EasyMock.java:499)
 at net.sourcesky.study.easymock.tutorial.PartialClassMockTest.testToStringMethod(PartialClassMockTest.java:74)

 

    可以看到明显是EasyMock.expect(service.toString()).andReturn("abc"); 这里的record没有成功。

 

分享到:
评论

相关推荐

    easymock2-javadoc-2.5.2-12.el7.noarch.rpm

    离线安装包,亲测可用

    easymock2-2.5.2-12.el7.noarch.rpm

    离线安装包,亲测可用

    powermock-easymock-junit-1.6.1.zip

    在"powermock-easymock-junit-1.6.1.zip"这个压缩包中,包含了这些工具的特定版本。 首先,我们来了解一下EasyMock。EasyMock是一个模拟框架,它允许开发者创建预期的交互(mock objects)并验证对象之间如何进行...

    powermock-easymock-junit-1.5.4.zip

    这个压缩包"powermock-easymock-junit-1.5.4.zip"很可能包含了这三个库的特定版本1.5.4,便于开发者下载和集成到自己的项目中。 首先,我们来详细了解一下PowerMock。PowerMock是一个扩展了其他模拟框架(如...

    easymock详解教程

    Partial class mocking是指模拟类的部分方法,而其他方法保持不变。这种技术适用于需要模拟部分行为同时保留类的部分真实行为的情况。 - **创建partial mock**:使用`EasyMock.createPartialMock`方法来创建部分...

    easymock-3.2.jar

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

    easymock-2.5.2.jar

    easymock-2.5.2.jar easymock-2.5.2.jar 单元测试

    easymock-3.1.jar

    easymock需要用到的包,没有它不行,easymock-3.1.jar

    easymock-4.0-bundle

    EasyMock 是一套用于通过简单的方法对于给定的接口生成 Mock 对象的类库。它提供对接口的模拟,能够通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock 对象返回指定...

    easymockclassextension-3.1

    扩展架包啊...easymockclassextension-3.1

    easymock教程.pdf

    easymock教程 easymock是一种流行的mocking框架,用于单元测试中模拟依赖对象的行为。下面是关于easymock的详细知识点: ### easymock的基本概念 * Mock对象:是一种虚拟对象,模拟真实对象的行为,用于单元测试...

    easymockclassextension-3.0.jar

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

    EasyMock 3.1相关jar(所有)

    还在为EasyMock使用时出异常而烦恼? 本压缩包包含除了Junit4之外easyMock3.1所用到的所有相关jar包,junit4可自己导入eclipse自带的即可 本压缩包包括: asm.jar cglib.jar objenesis.jar等 其中asm与cglib已兼容,放心...

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

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

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

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

    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完整包名] 进行安装

    easymock.jar,easymockclassextension.jar

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

    easymockclassextension-2.4.jar

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

    easymock教程

    - **Partial Class Mocking**:允许对一个类的部分方法进行Mock操作,而其他方法保持原有行为不变。 ##### 1.13 运行时返回值或者异常 - **动态设定返回值**:在测试过程中,可以根据不同的条件设定不同的返回值。...

Global site tag (gtag.js) - Google Analytics