[
vmassol
]
12:10, Sunday, 9 November 2003
Joel Shellman has coded an extension (easymock-patch-1.0.jar) of EasyMock which allows to mock class (and not only interfaces).
To use it:
- put the extension jar in front of the easymock jar in your classpath (it works with Easymock 1.0 only, not with the new 1.0.1b which has modifications for extending Easymock). It overrides the
MockControl
class by a new one accepting a class as parameter as shown below.
- add cglib to your classpath (I've tried it with version rc2-1.0).
- add bcel to your classpath (I've tried it with version 5.1).
Here's an example. First let's start by the class we wish to mock:
package test;
public class Calculator
{
private int amount;
public Calculator(Integer amount)
{
this.amount = amount.intValue();
}
public int compute()
{
return this.amount;
}
}
Here's now the class we wish to test (it uses the Calculator class):
package test;
public class Account
{
public int computeBalance(Calculator calculator)
{
return calculator.compute();
}
}
Now, here's our test of computeBalance
. Notice that we are mocking the Caculator
class:
package test;
import org.easymock.MockControl;
import junit.framework.TestCase;
public class AccountTest extends TestCase
{
public void testComputeBalance()
{
Account test = new Account();
MockControl control = MockControl.createControl(Calculator.class,
new Class[]{Integer.class}, new Object[]{new Integer(5)});
Calculator mock = (Calculator) control.getMock();
mock.compute();
control.setDefaultReturnValue(10);
control.replay();
int result = test.computeBalance(mock);
assertEquals(10, result);
}
}
Note: I don't know how to instantiate a constructor taking primitive types. Don't know if it is supported.
That's nice. However, there are a few drawbacks I can see:
- It doesn't encourage refactoring and creating interfaces (which is the right way to go in most cases). However, it can still be useful in some cases like when mocking third party classes which do not have interfaces (and there are quite a lot of them, especially in the JDK...)
- It doesn't work with final classes. Thus not possible to mock the JDK's URL class for example. It also won't work with private constructors of course
- It forces to know the constructor values when creating the mock
- It still doesn't help in cases where it is no easy to introduce the mock in the class under test. In that regards, it's less powerful than interception (a la AOP).
So it's not a silver bullet but it will certainly help in cases where you have no control over the sources (like when using third-party libraries.