Testing with Mock Objects
• A mock object is an object created to stand in for
an object that your code will be collaborating
with. Your code can call methods on the mock
object, which will deliver results as set up by
your tests.
• In other words, in a fine-grained unit test, you
want to test only one thing. To do this, you can
create mock objects for all of the other things
that your method/object under test needs to
complete its job.
Testing with Mock Objects
• Example
– Suppose we have a system that allows us
to transfer money from one bank account
to another.
– We want to test just the transfer method
which resides in the AccountService class
and uses an AccountManager to retrieve
Accounts, all of which are stored in a
database.
AccountService AccountManager
DB
Account
Testing with Mock Objects
//from JUnit in Action
public class AccountService {
private AccountManager accountManager;
public void setAccountManager(AccountManager manager) {
[Link] = manager;
}
public void transfer(String senderId, String beneficiaryId, long amount) {
Account sender = [Link](senderId);
Account beneficiary = [Link](beneficiaryId);
[Link](amount);
[Link](amount);
[Link](sender);
[Link](beneficiary);
}
}
Testing with Mock Objects
//from JUnit in Action
public interface AccountManager{
Account findAccountForUser(String userId);
void updateAccount(Account account);
}
• We assume there is a class that
implements the AccountManager
interface and interacts with the
database.
• We want to create a mock object in
place of the real thing.
• Account is simple enough that we will
use the actual class.
Testing with Mock Objects
//from JUnit in Action
import [Link];
public class MockAccountManager implements AccountManager {
private Hashtable accounts = new Hashtable();
public void addAccount(String userId, Account account)
{
[Link](userId, account);
}
public Account findAccountForUser(String userId)
{
return (Account) [Link](userId);
}
public void updateAccount(Account account)
{
// do nothing
}
}
Testing with Mock Objects
//from JUnit in Action
public class TestAccountService extends TestCase{
public void testTransferOk() {
MockAccountManager mockAccountManager =
new MockAccountManager();
Account senderAccount = new Account("1", 200);
Account beneficiaryAccount = new Account("2", 100);
[Link]("1", senderAccount);
[Link]("2", beneficiaryAccount);
AccountService accountService = new AccountService();
[Link](mockAccountManager);
[Link]("1", "2", 50);
assertEquals(150, [Link]());
assertEquals(150, [Link]());
}
}
Testing with Mock Objects
• Tests use production code.
• Sometimes a test pushes you to change
your production code to make it more
testable, usually making it more flexible
and less coupled to other objects.
• Mock Objects are notorious for improving
your production code.
EasyMock
• EasyMock is a third-party library for
simplifying creating mock objects
• Download EasyMock1.2 for Java1.3
from [Link]
– EasyMock 2.0 depends on Java 1.5
• Extract download
• Add [Link] to project
Testing Bank with EasyMock
package bank;
import [Link];
import [Link]; Import MockControl
import [Link];
public class TestBank extends TestCase {
private Bank b;
private MockControl control;
private Collection mock;
protected void setUp() { Collection is mock.
control = [Link]([Link]); We want to test Bank,
mock = (Collection) [Link]();
not Collection
b = new Bank(mock);
}
public void testNumAccounts() { Recording what we we expect:
[Link]();
[Link](7);
size() should be called, returning 7
[Link]();
Turn on mock with replay()
assertEquals([Link](),7);
[Link]();
Check expectations with verify()
}
}
Testing getLargest() with
package bank;
EasyMock
import [Link];
import [Link];
import [Link];
public class TestBank extends TestCase {
…
public void testGetLargest() {
control = [Link]([Link]);
SortedSet mock = (SortedSet) [Link]();
b = new Bank(mock);
[Link](); last() should be called on mock
try{
[Link](new Account("Richie Rich",77777,99999.99));
[Link]();
assertEquals([Link]().getBalance(),99999.99,.01);
} catch (Exception e) { fail("testGetLargest should not throw exception"); }
[Link]();
}
}
When to use Mock Objects
• When the real object has non-deterministic
behavior (e.g. a db that is always changing)
• When the real object is difficult to set up
• When the real object has behavior that is
hard to cause (such as a network error)
• When the real object is slow
• When the real object has (or is) a UI
• When the test needs to query the object, but
the queries are not available in the real object
• When the real object does not yet exist
* from [Link]