云自无心水自闲

天平山上白云泉,云自无心水自闲。何必奔冲山下去,更添波浪向人间!
posts - 288, comments - 524, trackbacks - 0, articles - 6
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
本文将简单介绍如何使用PowerMock和Mockito来mock
1. 构造函数
2. 静态函数
3. 枚举实现的单例
4. 选择参数值做为函数的返回值
5. 在调用mock出来的方法中,改变方法参数的值

一点简要说明:Mockito其实已经可以满足大部分的需求,但是它的实现机制是使用cglib来动态创建接口的类的实例。但是这种实现方式不能用于构造函数和静态函数,因为那需要使用类的字节码(比如使用javassist). 所以我们才需要结合使用PowerMock.

1. mock构造函数, 如果有代码没有使用DI注入依赖实例,在单元测试中可以使用PowerMock来模拟创建对象。
注意的开始两行的2个注解 @RunWith 和 @PrepareForTest
@RunWith比较简单,后面始终是PowerMockRunner.class
@PrepareForText后面需要加的是调用构造函数的类名,而不是有构造函数的类本身。
在下面的例子中,我们要测试的类是:Helper, 在Helper类中调用了Somthing类的构造函数来创建实例。
@RunWith(PowerMockRunner.class)
@PrepareForTest(Helper.
class)
public class HelperTest {
  @Mock
  
private Something mockSomething;
      
  @InjectMocks
  
private Helper helper;
      
  @Test
  
public void doSomething() throws Exception {
      String argument 
= "arg";
          
      PowerMockito.whenNew(Something.
class).withArguments(argument).thenReturn(mockSomething);
         
      // 调用需要测试方法
      helper.doSomething(argument);
         
      // 进行验证
      verify(mockSomething).doIt();
  }
}


public class Helper {
  public void doSomething(String arg) {
      Something something = new Something(arg);
      something.doit();
  }
}


2,mock 静态函数, 单例模式就是一个典型的会调用静态函数的例子。 注意要点与mock构造函数相同。
class ClassWithStatics {
  
public static String getString() {
    
return "String";
  }

  
public static int getInt() {
    
return 1;
  }
}

@RunWith(PowerMockRunner.
class)
@PrepareForTest(ClassWithStatics.
class)
public class StubJustOneStatic {
  @Test
  
public void test() {
    PowerMockito.mockStatic(ClassWithStatics.
class);

    when(ClassWithStatics.getString()).thenReturn(
"Hello!");

    System.out.println(
"String: " + ClassWithStatics.getString());
    System.out.println(
"Int: " + ClassWithStatics.getInt());
  }
}

3。mock枚举实现的单例
SingletonObject.java
public enum SingletonObject { 
    INSTANCE
;
    private
int num;
    protected
void setNum(int num) {
        this.num = num;
    }
    public int getNum() {
        return
num;
    }

}
SingletonConsumer.java

public class SingletonConsumer {
    public String consumeSingletonObject() { 
        return
String.valueOf(SingletonObject.INSTANCE.getNum());
    }
}
SingletonConsumerTest.java
@RunWith(PowerMockRunner.class) 
@PrepareForTest({SingletonObject.class})
public class SingletonConsumerTest {
    @Test public void testConsumeSingletonObject() throws Exception {
        SingletonObject
mockInstance = mock(SingletonObject.class);
        Whitebox
.setInternalState(SingletonObject.class, "INSTANCE", mockInstance);
        when
(mockInstance.getNum()).thenReturn(42);
        assertEquals
("42", new SingletonConsumer().consumeSingletonObject());
    }
}
4。返回参数值做为函数返回值。
mockito 1.9.5之后,提供一个方便的方法来实现这个需要,在这之前可以使用一个匿名函数来返回一个answer来实现。
when(myMock.myFunction(anyString())).then(returnsFirstArg());
其中returnsFirstArg()是org.mockito.AdditionalAnswers中的一个静态方法。
在这个类中还有其他的一些类似方法
returnsSecondArg()
returnsLastArg()
ReturnsArgumentAt(int position)

5. 在调用mock出来的方法中,改变方法参数的值
when( myMock.someMethod( any( List.class ) ) ).thenAnswer( ( new Answer<Void>() {
    @Override
    
public Void answer( InvocationOnMock invocation )
            
throws Throwable {
        Object[] args 
= invocation.getArguments();
        List arg1 
= (List)args[0];
        arg1.add(
"12345");
        
return null;
    }
} ) );



Verifying with generic parameters
verify(someService).process(Matchers.<Collection<Person>>any());
verify(adunoMasterBaseProcessor).processBinFiles( anyListOf(File.class) );



只有注册用户登录后才能发表评论。


网站导航: