• easymock入门贴


    from:http://macrochen.iteye.com/blog/298032

    关于EasyMock常见的几个问题, 这里(http://ozgwei.blogspot.com/2007/06/easymock2-quirk.html)有几点, 我做个翻译: 
    ★EasyMock在录制的时候最典型的写法: 

    Java代码  收藏代码
    1. expect(mockEmployeeRepository.findByFirstNameAndLastName("John", "Doe")).andReturn(employees);  


    ★如果有个要录制的方法只知道类型不知道具体的值, 可以这样写: 

    Java代码  收藏代码
    1. expect(mockEmployeeRepository.findBySpecification(isA(EmployeeSearchSpecification.class))  
    2. .andReturn(employees);  



    ★出现这样的异常: 
    java.lang.IllegalStateException: 2 matchers expected, 1 recorded. 
    可能是设置mock方法的期望调用方式时, 既使用了isA的方式来指定参数, 又使用了一个具体值来作为参数 
    比如这样写: 

    Java代码  收藏代码
    1. expect(mockEmployeeRepository.findByDepartmentAndSpecification("HR",   
    2. isA(EmployeeSearchSpecification.class)).andReturn(emplooyees);  


    正确的写法: 

    Java代码  收藏代码
    1. expect(mockEmployeeRepository.findByDepartmentAndSpecification(eq("HR"),  
    2. isA(EmployeeSearchSpecification.class)).andReturn(employees);  



    ★andReturn()只是用于当mock对象的方法需要有返回值的情况下,手动设置这个方法的返回值给调用的测试类的。在本例中methodABC (arguments,……)方法就需要在recorder的时候用andReturn()方法指定返回值给TargetClass。如果对于有返回值的方法不指定其返回值,在测试的时候会抛出”java.lang.IllegalStateException: missing behavior definition for the preceeding method call XXX”异常。 

    ★一般不能这样写: 

    Java代码  收藏代码
    1. EasyMock.expect(itemPropertyManager.processPublishOrEditSpu(EasyMock.isA(SpuDO.class),  
    2. EasyMock.isA(BaseResultDO.class))).andReturn(EasyMock.isA(BaseResultDO.class));  


    而应该这样写: 

    Java代码  收藏代码
    1. EasyMock.expect(itemPropertyManager.processPublishOrEditSpu(EasyMock.isA(SpuDO.class),  
    2. EasyMock.isA(BaseResultDO.class))).andReturn(null));  


    否则会抛出这样的异常: 

    引用

    java.lang.IllegalStateException: matcher calls were not used outside expectations 
    at org.easymock.internal.RecordState.replay(RecordState.java:72) 
    at org.easymock.internal.MocksControl.replay(MocksControl.java:57) 
    at org.easymock.EasyMock.replay(EasyMock.java:1280) 


    也就是说, 返回值必须给一个具体的值, 而不能只指定返回值类型 

    ★在实用expect来设置mock方法的期望调用方式时, 如果使用到基本类型, 但是又不要基本类型的值, 一般不要这样写: 

    Java代码  收藏代码
    1. EasyMock.expect(  
    2.                     keywordsChecker.checkNormalKeywords(EasyMock  
    3.                             .isA(String.class), EasyMock.isA(Long.class),  
    4.                             EasyMock.isA(String.class))).andReturn("");  


    而应该这样写: 

    Java代码  收藏代码
    1. EasyMock.expect(keywordsChecker.checkNormalKeywords(EasyMock.isA(String.class), EasyMock.anyLong(),   
    2. EasyMock.isA(String.class))).andReturn("");  



    ★EasyMock还有一个很让人郁闷的地方, 比如一个方法的参数可能为null, 而你在测试的时候又恰恰传了一个空值, 则这个测试是没法通过的, 会出现类似下面的异常: 

    引用
    java.lang.AssertionError: 
      Unexpected method call checkFixKeywords(null, 50010815): 
        checkFixKeywords(isA(java.lang.String), <any>): expected: 1, actual: 0 
        checkNormalKeywords(isA(java.lang.String), <any>, isA(java.lang.String)): expected: 1, actual: 0 
    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) 
    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:45)


    这也就要求被测试的方法, 参数不能传递空值. 
    经过跟踪这个应该是EasyMock的一个bug: 

    Java代码  收藏代码
    1. public class InstanceOf implements IArgumentMatcher {  
    2.   
    3.     private final Class<?> clazz;  
    4.   
    5.     public InstanceOf(Class clazz) {  
    6.         this.clazz = clazz;  
    7.     }  
    8.   
    9.     public boolean matches(Object actual) {  
    10.         // 问题在这里:  
    11.         return (actual != null) && clazz.isAssignableFrom(actual.getClass());  
    12.         // 应该这样写:  
    13.         return (actual == null) || clazz.isAssignableFrom(actual.getClass());  
    14.     }  
    15.   
    16.     public void appendTo(StringBuffer buffer) {  
    17.         buffer.append("isA(" + clazz.getName() + ")");  
    18.     }  
    19. }  



    不过这个问题也不是不能绕过, 我用了下面的做法: 

    Java代码  收藏代码
    1. EasyMock.expect(  
    2.         keywordsChecker.checkFixKeywords(  
    3.                 (String) EasyMock.isNull(), EasyMock.anyLong()))  
    4.         .andReturn("");  
    5. EasyMock.expect(  
    6.         keywordsChecker.checkFixKeywords(  
    7.                 EasyMock.isA(String.class), EasyMock.anyLong()))  
    8.         .andReturn("").anyTimes();  


    后来我问了一下EasyMock开发者Tammo Freese, 看来不是能算一个bug, 他做了如下的回答: 

    引用
    this is expected behavior, and it is also documented. 
    The isA() matcher does the same thing as instanceof , so for null, it returns false. 

    If you would like to match any Object, use 
       anyObject() 
    If you would like to match either Strings or null, use 
       or(isA(String.class), isNull())


    这里录制了两个expect:将null和非空值分开, 但是第二个的返回值注意加上anyTimes(), 因为我的第二种情况会调用多次, 如果两种情况都会调用多次, 则都加上该方法即可, 否则会出现类似下面的异常: 

    引用
    java.lang.AssertionError: 
      Unexpected method call checkFixKeywords("new test", 50010815): 
        checkFixKeywords(isA(java.lang.String), <any>): expected: 1, actual: 1 (+1) 
        checkNormalKeywords(isA(java.lang.String), <any>, isA(java.lang.String)): expected: 1, actual: 0 
    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:32) 
    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:61)



    ★静态方法是没法用EasyMock进行mock的 

    ★如果需要expect的方法没有返回值, 应该这样写: 
    先执行mock的要调用的方法, 然后调用EasyMock.expectLastCall().anyTimes(); 

    ★如果是对具体类进行mock, 则需要使用org.easymock.classextension.EasyMock去替换org.easymock.EasyMock, 当然这个需要加入对easymockclassextension的引用, 具体使用上则没有区别, 如果采用maven构建工程, 则可以采用下面的写法: 

    Xml代码  收藏代码
    1. <!-- mock 相关 -->  
    2.        <dependency>  
    3.            <groupId>org.easymock</groupId>  
    4.            <artifactId>easymock</artifactId>  
    5.            <version>2.4</version>  
    6.        </dependency>  
    7.        <dependency>  
    8.         <groupId>org.easymock</groupId>  
    9.         <artifactId>easymockclassextension</artifactId>  
    10.         <version>2.2.1</version>  
    11.        </dependency>  
    12.        <!-- mock 相关 end-->  



    ★通常对一个方法进行测试的时候, mock一个对象的情况比较多见, 于是我写了下面的一个比较通用的抽象类: 

    Java代码  收藏代码
    1. public abstract class AbstractMockExecutor<T> {  
    2.     protected T mock;  
    3.   
    4.     /** 
    5.      * @param clazz 
    6.      * @return 
    7.      */  
    8.     protected T createMock(Class<T> clazz) {  
    9.         mock = EasyMock.createMock(clazz);  
    10.         return mock;  
    11.     }  
    12.   
    13.     public void execute() throws Exception {  
    14.         record();  
    15.         EasyMock.replay(mock);  
    16.         invoke();  
    17.         verify();  
    18.     }  
    19.   
    20.     /** 
    21.      * 创建mock对象, 并对要mock的方法进行方法录制, 必须在该方法中手动调用{@link #createMock(Class)}方法.<br> 
    22.      * 该方法的一般做法如下: 
    23.      *  
    24.      * <pre> 
    25.      * createMock(MockClass); 
    26.      * EasyMock.expect(mock.mockMethod(mockArgument...)).andReturn( 
    27.      *      mockResult); 
    28.      * BeanObject.setter(mock); 
    29.      * </pre> 
    30.      *  
    31.      * @throws Exception 
    32.      */  
    33.     protected abstract void record() throws Exception;  
    34.   
    35.     /** 
    36.      * 调用经过mock之后的执行过程 
    37.      */  
    38.     protected abstract void invoke() throws Exception;  
    39.   
    40.     /** 
    41.      * 验证mock是否正确 
    42.      */  
    43.     public void verify() {  
    44.         EasyMock.verify(mock);  
    45.     }  
    46. }  



    2012-01 更新: 
    有时候我们会碰到这样的异常信息: 
    matcher calls were used outside expectations 
    后来在网上google了一把, 这里有个说明. 
    简单的说就是andReturn(xxx)中的xxx不能使用EasyMock.anyObject()这样的方法来指定结果. 但是它没有说解决办法. 这里可以利用andAnswer(), 比如这样写: 

    Java代码  收藏代码
      1. final AtomicLong count = new AtomicLong(10000L);  
      2. EasyMock.expect(db.count()).andAnswer(new IAnswer<Long>() {  
      3.     @Override  
      4.     public Long answer() throws Throwable {  
      5.         return count.getAndIncrement();  
      6.     }  
      7. }).times(10);  
  • 相关阅读:
    「Luogu2397」 yyy loves Maths VI (mode)
    「Luogu2014」 选课
    「Luogu2972」 [USACO10HOL]岩石和树木Rocks and Trees
    中国剩余定理
    点双连通分量
    Miller_Rabin大质数检验
    manachaer算法
    Kruskal重构树
    世界,你好!
    [Luogu P1450] [HAOI2008]硬币购物 背包DP+容斥
  • 原文地址:https://www.cnblogs.com/heidsoft/p/3833195.html
Copyright © 2020-2023  润新知