1. 如何校验expectations中的规则?
使用JMock时,一般会通过如下代码指定expectations。
private Mockery context = new Mockery();
context.checking(new Expectations() {
{
... expectations go here ...
}
});
为了校验expectations中的规则是否都满足,可以在测试完成后通过增加context.assertIsSatisfied()方法来验证expectations是否满足。
//test assertions and test logic code.
context.assertIsSatisfied();
若校验不成果,测试将失败。
one(mockObject) 以后会depreacted; 即one方法即将过时。所以因该使用oneOf(mockObject) 来代替. oneOf是2.51版中的内容。
3. 如何设定使用expectations的语法来指定同一个方法连续调用时返回不同的值?
有两种方法,第一种就是直接通过多次调用will(returnValue(X))来指定。如
oneOf (anObject).doSomething(); will(returnValue(10));
oneOf (anObject).doSomething(); will(returnValue(20));
oneOf (anObject).doSomething(); will(returnValue(30));
第一次调用时会返回10,第二次会返回20,第三次会返回30.
然而第一一种方法会增加维护成本,且缺乏可控性。JMock提供了第二种方法,即通过onConsecutiveCalls的action来实现返回不同的返回值。如:
atLeast(1).of (anObject).doSomething();
will(onConsecutiveCalls( returnValue(10), returnValue(20), returnValue(30)));
这里atLeast (1)表明doSomething方法将至少被调用一次,但不超过3次。且调用的返回值分别是10、20、30.
在will方法中直接使用throwException的action。参考如下语法:
oneOf (anObject).doSomething(); will(throwException(new UserDefinedException());
参考Jmock的文档,调用次数可以通过 oneOf,exactly(times).of, atLeast(times).of, atMost(times).of, between(min, max).of, allowing, ignoring, never 等来指定。具体含义见下表。
JMock defines the following cardinalities:
one | The invocation is expected once and once only. |
exactly(times).of | The invocation is expected exactly n times. Note: one is a convenient shorthand for exactly(1). |
atLeast(times).of | The invocation is expected at least n times. |
atMost(times).of | The invocation is expected at most n times. |
between(min, max).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. |
需要强调的是allowing和ignoring的规则不会破坏 context.assertIsSatisfied()的校验。
根据JMock的cookbook。如果方法的调用是allowing的,哪么在测试时,这个方法允许被调用,并且如果方法未被调用测试仍然会通 过。反之,如果一个方法是expected的(即通过one,oneOf,exactly(times).of, atLeast(times).of, atMost(times).of, between(min, max).of 等指定次数的),则该方法必须满足次数的要求,否则测试将失败。
当需要指定方法调用次序时,可以首先声明一个JMock 的sequence对象。
final Sequence sequenceName= context.sequence("sequenceName");
然后通过增加inSequence(sequenceName)的语法来指定不同方法的调用次序:
oneOf (turtle).forward(10); inSequence(sequenceName);
oneOf (turtle).turn(45); inSequence(sequenceName);
atMost(5).of (turtle).forward(10); inSequence(sequenceName);
oneOf (turtle).backward(20); inSequence(sequenceName);
这样方法被调用的顺序必须按照forwar、turn、forward、backward的顺序来进行。此外如果Sequence中的方法的expectations是allowing的,则将被Sequence忽略。
状态机state和Sequence的使用方法类似。首先声明state。
//构建状态机,并确定初始状态为"initialState"。 final States stateMachineName = context.states("stateMachineName ").startsAs("initialState");
然后通过如下语法来使用
The following clauses constrain invocations to occur within specific states and define how an invocation will change the current state of a state machine.
when(state-machine.is(”state-name”)); | Constrains the last expectation to occur only when the state machine is in the named state. |
when(state-machine.isNot(”state-name”)); | Constrains the last expectation to occur only when the state machine is not in the named state. |
then(state-machine.is(”state-name”)); | Changes the state of state-machine to the named state when the invocation occurs. |
实例:
//声明状态机" pen",初始状态为"up".
final States pen = context.states("pen").startsAs("up");
//penDown执行后,状态机迁移为"down".
oneOf (turtle).penDown(); then(pen.is("down"));
//forward执行的条件是状态机处于"down"状态;
oneOf (turtle).forward(10); when(pen.is("down"));
//turn执行的条件是状态机处于"down"状态.
oneOf (turtle).turn(90); when(pen.is("down"));
//forward执行的条件是状态机处于"down"状态;
oneOf (turtle).forward(10); when(pen.is("down"));
//penUp执行后,状态机迁移到"up"状态.
oneOf (turtle).penUp(); then(pen.is("up");