EasyMock教程-运行时返回值或者异常 文章分类:软件开发管理

easymock教程-运行时返回值或者异常

来至:http://skydream.iteye.com/blog/834158

 

 

        前面的教程中,我们看到easymock可以通过expect方法来设定mock方法的返回值或者异常,但是注意这些案例中设置的返回值都是在调用被测试 的类的方法前就已经确定下来的,即我们其实在测试类的代码运行前(实际是在EasyMock.replay()方法调用前)就已经"预知"了返回结果。

 

    但是在某些情况下,我们可能无法预知返回值,比如我们需要根据输入的参数值来决定返回什么,而这个参数可能无法在record阶段获得。因此在mock方法中我们无法在record阶段就决定应该返回什么。

 

    对于这种场景,easymock提供了IAnswer接口和andAnswer()方法来提供运行时决定返回值或者异常的机制。

 

    我们来看一个简单的例子:

     public   class  Business  {
        
private  Service service;

        
public   void  execute()  {
            
int  count  =  ramdonInt();
            
int  result  =  service.execute(count);
        }


        
public   void  setService(Service service)  {
            
this .service  =  service;
        }


        
private   int  ramdonInt()  {
            Random random 
=   new  Random();
            
return  random.nextInt()  /   10000 ;
        }

    }


    
public   interface  Service  {
        
public   int  execute( int  count);
    }

    在Business的execute()方法中,需要调用service.execute(int count)方法,而传入的参数count是需要运行时才能确定的,这里为了简单我们random了一个int来模拟这种情况。

 

    然后看测试案例

    @Test
    
public   void  testRuntimeReturn()  {
        Business business 
=   new  Business();
        Service service 
=  EasyMock.createMock(Service. class );
        business.setService(service);
        EasyMock.expect(service.execute(EasyMock.anyInt())).andAnswer(
new  IAnswer < Integer > ()  {
            
public  Integer answer()  throws  Throwable  {
                Integer count 
=  (Integer) EasyMock.getCurrentArguments()[ 0 ];
                
return  count  *   2 ;
            }

        }
);

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

    这里我们通过EasyMock.expect(service.execute(EasyMock.anyInt()))来接受任意值的count参数输 入,andAnswer(new IAnswer<Integer>() {}) 让我们可以指定一个IAnswer的实现类来给出返回值。在这个IAnswer的实现类中,我们通过 EasyMock.getCurrentArguments()[0]获取到service.execute()方法的第一个参数,然后简单的运用 count*2规则给出返回值。这里的EasyMock.getCurrentArguments()方法可以获取到运行时的参数列表,不过注意这个方法 对重构不够友好,如果参数列表发生变化则必须手工修改对象的获取参数的代码。

 

    下面是一个运行时抛出异常的例子,简单起见我们通过设置exception的message来在错误信息中传递运行时的count值。

   @Test
    
public   void  testRuntimeException()  {
        Business business 
=   new  Business();
        Service service 
=  EasyMock.createMock(Service. class );
        business.setService(service);
        EasyMock.expect(service.execute(EasyMock.anyInt())).andAnswer(
new  IAnswer < Integer > ()  {
            
public  Integer answer()  throws  Throwable  {
                Integer count 
=  (Integer) EasyMock.getCurrentArguments()[ 0 ];
                
throw   new  RuntimeException( " count= "   +  count);
            }

        }
);

        EasyMock.replay(service);
        
try   {
            business.execute();
            fail(
" should throw RuntimeException " );
        }
  catch  (RuntimeException e)  {
            assertTrue(e.getMessage().indexOf(
" count= " !=   - 1 );
            
// get count from message
            EasyMock.verify(service);
        }

    }

    除了IAnswer接口外,easymock中还有另外一个方式可以完成类似的功能,就是使用andDelegate()方法,

     public   class  ServiceStub  implements  Service  {
        
public   int  execute( int  count)  {
            
return  count  *   2 ;
        }

    }


    @Test
    
public   void  testRuntimeReturn()  {
        Business business 
=   new  Business();
        Service service 
=  EasyMock.createMock(Service. class );
        business.setService(service);
        EasyMock.expect(service.execute(EasyMock.anyInt())).andDelegateTo(
new  ServiceStub());

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

    这里需要先创建一个Service类的实现类和一个实例,然后通过andDelegateTo()将这个stub的实例传进去,注意这里delegate进去的实例必须是mock对象接口相同。

 

    delegateTo方式实际上是我们手工创建了stub(mock和stub的概念及差别请参考本教程的"mock和stub"一文),这和我们使用 easymock的初衷有所违背。而且当这个接口有众多方法时,创建这样一个stub会显得很痛苦,不如使用IAnswer方便直接。

你可能感兴趣的:(软件测试,Blog)