code_money_guji's Blog

Happy coding

TDD 单元测试 JMock<1>

参考资料:

         http://www.jmock.org/cookbook.html  JMock的cookbook 使用手册

         http://www.ibm.com/developerworks/cn/java/j-lo-testpartten/  使用设计模式使得单元测试更加简单.

         <<Agile Java>> 敏捷开发 TDD思想相关书籍

         http://groovy.codehaus.org/Using+JMock+with+Groovy//Groovy 中使用JMock

 

java JMock 编写单元测试:

       导入相关的jar,引入相关的包:

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import static org.hamcrest.Matchers.*;

     初始化:  要使用JMock模拟一般的java类时,就需要CGLib的"增强字节码"能力.而不是java一般的动态代理.

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

 

  mock 一般方法[无返回值]:

context.checking(new Expectations() {{
      oneOf (subscriber).receive(message);
}});

   mock 具有返回值的方法:

//返回一个迭代器.方法无参数
context.checking(new Expectations() {{
    oneOf (YourMockClass).mockMethod(); 
    will(returnIterator(testReturnedItreator));
}});

//返回一个对象.方法无参数
context.checking(new Expectations() {{
    oneOf (YourMockClass).mockMethod();
    will(returnValue(testReturnedItreator));
}});

//返回一个对象,方法参数是任何的String类型
context.checking(new Expectations() {{
    oneOf (YourMockClass).mockMethod(with(any(String.class)));
     will(returnValue(testReturnedObject));
}});

 注意: 上述的oneOf() 已经指定mock对象的mock方法只会被调用一次!!! 如下的示例是能够调用"至少一次",并针对每一次的调用可以指定不同的返回值: 

context.checking(new Expectations() {{
            atLeast(1).of(dbHelper).getUserById(with(any(String.class)));
                 will(onConsecutiveCalls(
                         returnValue(highRiskUser),
                         returnValue(nomalUser)
                                  
                 ));                  
        }});

//..其他类似的方法见:http://www.jmock.org/returning.html

 

  mock 异常的

 

context.checking(new Expectations() {{
			allowing(dbHelper).getUserById(with(any(String.class)));
			will(Expectations.throwException(MOCK_SQL_EXCETION)); //模拟一个SQLException的发生.
        }});

 

mock 方法的不同参数,并且返回不同的结果[包括抛出异常情况]

allowing (calculator).add(1,1); will(returnValue(3));
allowing (calculator).add(2,2); will(returnValue(5));
allowing (calculator).sqrt(-1); will(throwException(new IllegalArgumentException());

模拟方法被调用的次数:
one   (calculator).load("x"); will(returnValue(10));  //调用一次,
never (calculator).load("y");  //从不调用

 

 

mock matchers: 在new Expectations(){....}中, 一般会加入 allowing(...).add(<A>),A区域称为"参数匹配"区域. jmock允许我们做一些模糊的参数匹配,如下:

allowing (calculator).sqrt(with(lessThan(0)); will(throwException(new IllegalArgumentException());
//参数小于0,抛出异常
oneOf (log).append(with(equal(Log.ERROR)), with(stringContaining("sqrt")); //两个参数, 一个equasls(Log.ERROR),另一个是包含了“sqrt”的参数;
oneOf (mock).doSomething(with(aNull(String.class)), aNonNull(String.class)));
oneOf (mock).doSomething(with(eq(1)), with(any(String.class)));
oneOf (mock).doSomething(with(not(eq(1)));
oneOf (mock).doSomething(with(allOf(stringContaining("hello"), stringContaining("world"))));//参数是一个String包括hello,world两个单词
oneOf (mock).doSomething(with(anyOf(stringContains("hello"),stringContains("howdy"))));//参数是一个String包括了hello或者world

 

 

mock 匹配方法的调用次数:

one The invocation is expected once and once only.
exactly(n).of The invocation is expected exactly n times. Note: one is a convenient shorthand for exactly(1).
atLeast(n).of The invocation is expected at least n times.
atMost(n).of The invocation is expected at most n times.
between(minmax).of The invocation is expected at least min times and at most max times.
allowing The invocation is allowed any number of times but does not have to happen.
ignoring The same as allowing. Allowing or ignoring should be chosen to make the test code clearly express intent.
never The invocation is not expected at all. This is used to make tests more explicit and so easier to understand.

 

 

mock 忽略相关的mock对象的所有方法,这里的忽略是返回一个"默认"的值:

ignoring (hibernateSessionFactory);
Return Type "Zero" Value
boolean false
numeric type zero
String "" (empty string)
Array Empty array
Mockable type A mock that is ignored
Any other type null