单元测试技术JMOCK引用

来源:互联网 发布:图纸软件哪个好 编辑:程序博客网 时间:2024/05/16 12:20

1:MAVEN配置
<dependency>
 <groupId>org.jmock</groupId> 
 <artifactId>jmock-junit4</artifactId> 
 <version>2.5.1</version>
           <scope>test</scope>      
</dependency>
<dependency>
 <groupId>org.jmock</groupId> 
          <artifactId>jmock</artifactId> 
          <version>2.5.1</version>
            <scope>test</scope>       
</dependency>


2:步骤:
// 1:创建一个Mockery对象
 Mockery context = new Mockery();
 // 2:创建Mock对象,非常简单
 final Session t = context.mock(Session.class);
 // 3. 对Mock对象添加预定的期望
 context.checking(new Expectations(){
  {
  //Expectations的语法,需要放在一对大括号之内
  //oneOf(t).receive(message);
  //will(returnValue(message);
  //inSequence(seq);
  //其中期望类Expectations将在3.2节详细介绍
  }
  });

 
 //4. 被测试对象的业务逻辑调用

 //5. 查看Mock是否满足被测结果,代码如下:
 context.assertIsSatisfied();

3:详细如下:
Expectations的语法如下表所示:
invocation-count (mock-object).method(argument-constraints);  [必需]
inSequence(sequence-name);
when(state-machine.is(state-name));
will(action);
then(state-machine.is(new-state-name));
针对Mock对象模拟调用的每一个方法,都应该必须有一个应该必须有一个invocation-count子句,其余子句为可选。
下面对这几个表达式分别作简要的介绍:
invocation-count
invocation-count表示期望的方法的调用次数。其可选的表达形式如下表所示:
oneof / one 期望调用执行一次且仅一次
exactly(n).of 期望调用执行n次
atLeast(n).of 期望调用执行至少n次
atMost(n).of 期望调用执行至多n次
between(min, max).of 期望调用执行至少min次,至多max次
allowing / ignoring 期望调用执行任意多次,包括0次
never 不期望调用执行
具体使用如下所示:
exactly(4).of(subscriber).receive(message);
atMost(2).of(subscriber).receive(message); 
atLeast(4).of(subscriber).receive(message);
atLeast(2).of(subscriber).receive(message); 


二:模拟泛型接口
模拟泛型
public interface Juicer<T extends Fruit> {    Liquid juice(T fruit);}
那些行,虽然在语句结构和语义上都是正确的,但是产生了安全警告.为了避免这些警告,你必须使用@SuppressWarnings注释变量声明:
@SuppressWarnings("unchecked")
Juicer<Orange> orangeJuicer =(Juicer<Orange>) context.mock(Juicer.class, "orangeJuicer");

 @SuppressWarnings("unchecked")
Juicer<Coconut> coconutJuicer =(Juicer<Coconut>) context.mock(Juicer.class, "coconutJuicer");

三:使用jMock和ClassImposteriser模拟类
ClassImposteriser创建模拟实例不需要调用模拟类的构造函数.所以带有有参数或调用可覆盖的对象方法的构造函数的类可以被安全的模拟.然而ClassImposteriser不能创建最终类或最终方法的模拟.

private Mockery context = new Mockery() {{       
setImposteriser(ClassImposteriser.INSTANCE);   
}};

四:user、UserService、UserDao
对UserDao进行mock模拟,表达式如下:
userDAO = new Mock(UserDAO.class);       
userService.setUserDAO((UserDAO)userDAO.proxy());


userDAO.expects(once()).method("getUser").with(eq(1L)).will(returnValue(fakeUser));
1) userDAO.expects(once()):我们期望userDAO的某方法被执行一次,如果此方法未被执行,或者执行了二次以上,测试就不会通过
2) method("getUser"):这个期望被执行一次的方法名为userDAO.getUser()
3) with(eq(1L)):执行getUser()方法时,确认其传入的参数值为“1L”
4) will(returnValue(fakeUser)):上述条件均满足后,返回一个虚假的对象,即我们前面实例化的fakeUser。

对于Mock类有很多API可供使用比如:
isA(Class clz) 表示为某个类
isVoid 将will换成isVoid表示无返回值

异常测试:
  allowing(dao).find(id);will(throwException(new FindException()));//也可以throw RuntimeException  
可以在mock方法时做一些参数操作:
 allowing(srv).findUser(with(lessThan(10)));will(returnValue(user1));  


五:表达式如下:
invocation-count mock调用频率。oneOf表示调用一次后这个expections即失效。
mock-object mock对象。即上面Mockery创建的对象。
method 用mock代替实现接口的一个方法。所以mock必须使用接口编程。
argument-constraints mock参数条件。即mock指定方法的参数。
when … will…then … 类似于if .. else… 这样的语句。简单的条件表达式
action mock符合条件后,执行操作。一般是返回结果。或者抛出异常
state-machine 条件表达式。
下面详细讲解下expectations各个部分。
Invocation CountoneOf 只执行一次
exactly(n).of 执行指定n次
atLeast(n).of 至少执行n次
atMost(n).of 最多执行n次
between(min,max).of 可以执行min-max次
allowing 允许执行,不受限制
ignoring 功能同allowing类似。这里主要字面上区分allowing
never 不允许执行

Actionswill(returnValue(v)) 返回一个值。Object类型任意。集合类型不建议这里返回。虽然也可以
will(returnIterator(c)) 返回一个集合类型的值。
will(returnIterator(v1, v2, …, vn)) 返回一个集合类型的值。可以用多个,来分隔。
will(throwException(e)) 抛出一个异常。
will(doAll(a1, a2, …, an)) 嵌套执行多个actoin。不常用。

参数为对象:
allowing(loginCommand).setService(with(same(dataService)));
inSequence(classSequence);
will(returnValue(dataService));

 
 


六:mock类中的private
执行private方法,mock类中的私有方法:
 //DateUtil.class,要Mock的类  
new Expectations(DateUtil.class) {  
{  
  //执行DateUtil的now方法  
 invoke(DateUtil.class,"now");  
//期望方法返回的结果  
 result = mockDate();  
    }  
 };  
 Assert.assertEquals("2010-07-22 15:52:55", DateUtil.getCurrentDateStr()); 

mock 某个类的私有属性:
 @Test 
public void testPrivateFiled() {  
final DateUtil dateUtil =new DateUtil();  
new Expectations(dateUtil){  
  {  
this.setField(dateUtil, "count", 2);  
      }  
    };  
Assert.assertEquals(2, dateUtil.getCount());  

•关键词:Verifications 想验证被Mock的类的某个方法是否被调用
 new Verifications() {  
 {  
 remote.doSomething(anyInt);  
 times = 0;//调用次数,0表示上面方法不会被调用  
}  
};  

 

avatar-gen工具


public class TestLoginCommandExecutor {
 private Mockery classContext = null;
 private LoginCommandExecutor loginCommand = null;
 private Mockery interfaceContext = null;
 private DataService dataService = null;
 private Session session = null;
 private ResponseGenerator responseGenerator = null;

 @Before
 public void setUp() throws Exception {
  classContext = new Mockery() {
   {
    setImposteriser(ClassImposteriser.INSTANCE);
   }
  };
  loginCommand = classContext.mock(LoginCommandExecutor.class);
  interfaceContext = new Mockery();
  session = interfaceContext.mock(Session.class);
  dataService = interfaceContext.mock(DataService.class);
 }

 @After
 public void tearDown() throws Exception {
  loginCommand = null;
  classContext = null;
  interfaceContext = null;
  dataService = null;
  session = null;
  responseGenerator = null;
 }

 @Test
 public void testSetDataService() {
  classContext.checking(new Expectations() {
   {
    oneOf(loginCommand).setService(with(same(dataService)));
    will(returnValue(null));
   }
  });
  loginCommand.setService(dataService);
  classContext.assertIsSatisfied();
  Assert.assertNotNull("DataService为空!", dataService);
 }

 @Test
 public void testLoginExecutor() throws IOException {
  final String commandName = "Login";
  final Command command = new Command();
  command.addProperty("user", "admin");
  command.addProperty("password", "0f52903a303478324f8ffd479d300259");
  command.addProperty("version", "5.0");
  final ByteBuffer data = ByteBuffer.allocate(10000);
  interfaceContext.checking(new Expectations() {
   {
    oneOf(dataService).authorize("admin",
      "0f52903a303478324f8ffd479d300259");
    will(returnValue(2));

    oneOf(session).putAttribute(
      DataServiceServerConstants.USER_INFO, "admin");
    oneOf(session).putAttribute(
      DataServiceServerConstants.PASSWORD,
      "0f52903a303478324f8ffd479d300259");
    oneOf(session).changeState(DataServiceState.Idle);
   }
  });

  responseGenerator = new ResponseGenerator();
  responseGenerator.setCommandName(commandName);
  final LoginCommandExecutor login = new LoginCommandExecutor();
  login.setService(dataService);
  Assert.assertNotNull("DataService为空!", dataService);
  Assert.assertNotNull("Command为空!", command);
  login.execute(command, data, session, responseGenerator);
  Assert.assertNotNull("Session为空!", session);
  interfaceContext.assertIsSatisfied();
 }

 @Test
 public void testGetName() {
  final LoginCommandExecutor login = new LoginCommandExecutor();
  final String name = login.getName();
  Assert.assertEquals("Login", name);
 }


二:
        UploadServiceImpl uploadServiceImpl = new UploadServiceImpl();
 @Test
 public void testGetFile() {
  final TestSourceFile testSourceFile = new TestSourceFile();
  final int groupId = 6;
  final String fileName = "test.txt";
  interfaceMock.checking(new Expectations() {
   {
    oneOf(dataServiceDao).getFile(groupId, fileName);
    will(returnValue(testSourceFile));
   }
  });
  uploadServiceImpl.setDao(dataServiceDao);
  Assert.assertNotNull("DataServiceDao为空!", dataServiceDao);
  final TestSourceFile testSource = uploadServiceImpl.getFile(groupId,
    fileName);
  Assert.assertNotNull("TestSourceFile为空!", testSource);
  interfaceMock.assertIsSatisfied();
 }

 

 

 

 

 

 

 

 

 

 

原创粉丝点击