MockitovsEasyMockvsJMockit
1. 序章
1.1. 概要
この投稿では、モックについて説明します。それは何であるか、なぜそれを使用するのか、そしてJavaで最もよく使用されるモックライブラリのいくつかを使用して同じテストケースをモックする方法のいくつかの例です。 。
まず、モックの概念の正式/準正式な定義から始めます。 次に、テスト中のケースを提示し、各ライブラリの例をフォローアップして、いくつかの結論を出します。 選択したライブラリは、 Mockito 、 EasyMock 、およびJMockitです。
モッキングの基本をすでに知っていると感じた場合は、次の3つのポイントを読まずに、ポイント2にスキップできます。
1.2. モックを使用する理由
テスト(TDD、ATDD、またはBDD)を中心としたいくつかの駆動開発方法論に従ってすでにコーディングしていると仮定します。 または、単に、依存関係に依存してその機能を実現する既存のクラスのテストを作成したいということです。
いずれにせよ、クラスを単体テストするときは、その機能のみをテストし、依存関係の機能はテストしないようにします(実装を信頼するため、または自分でテストするため)。
これを実現するには、テスト対象のオブジェクトに、その依存関係を制御できる置換を提供する必要があります。 このようにして、極端な戻り値を強制したり、例外をスローしたり、時間のかかるメソッドを固定の戻り値に単純に減らしたりすることができます。
この制御された置換はモックであり、テストコーディングを簡素化し、テスト実行時間を短縮するのに役立ちます。
1.3. モックの概念と定義
Martin Fowlerによって書かれた記事からの4つの定義を見てみましょう。これは、モックについて誰もが知っておくべき基本事項をまとめたものです。
- ダミーオブジェクトは渡されますが、実際に使用されることはありません。 通常、これらはパラメータリストを埋めるために使用されます。
- Fake オブジェクトには機能する実装がありますが、通常、本番環境に適さないショートカットを使用します(メモリ内データベースが良い例です)。
- スタブは、テスト中に行われた呼び出しに対して定型の応答を提供します。通常、テスト用にプログラムされたもの以外にはまったく応答しません。 スタブは、「送信した」メッセージを記憶する電子メールゲートウェイスタブや、「送信した」メッセージの数だけなど、通話に関する情報を記録する場合もあります。
- Mocks は、ここで話していることです。オブジェクトは、受信することが期待される呼び出しの仕様を形成する期待値で事前にプログラムされています。
1.4. 嘲笑するかしないか:それが問題です
すべてをモックする必要はありません。 そのメソッド/機能をあざけるだけでは実際の利益はほとんど得られないため、統合テストを実行する方がよい場合があります。 LoginDao をテストするテストケース(次のポイントで示されます)では。
LoginDao はDBアクセスにサードパーティのライブラリを使用し、それをモックすることは、呼び出し用にパラメーターが準備されていることを確認することだけで構成されますが、呼び出しが必要なデータを返すことをテストする必要があります。
そのため、この例には含まれません(ただし、サードパーティライブラリ呼び出しのモック呼び出しを使用した単体テストと、サードパーティライブラリの実際のパフォーマンスをテストするためのDBUnitとの統合テストの両方を記述できます)。
2. テストケース
前のセクションのすべてを念頭に置いて、非常に典型的なテストケースと、モックを使用してテストする方法(モックを使用することが理にかなっている場合)を提案しましょう。 これは、後でさまざまなモッキングライブラリを比較できるようにするための共通のシナリオを作成するのに役立ちます。
2.1. 提案されたケース
提案されたテストケースは、階層化されたアーキテクチャを備えたアプリケーションでのログインプロセスです。
ログイン要求は、DAO(DB上のユーザー資格情報を検索する)を使用するサービスを使用するコントローラーによって処理されます。 各レイヤーの実装についてはあまり深く掘り下げず、各レイヤーのコンポーネント間の相互作用に焦点を当てます。
このようにして、 LoginController 、 LoginService 、およびLoginDAOが作成されます。 明確にするために図を見てみましょう:
2.2. 実装
次に、テストケースに使用される実装について説明します。これにより、テストで何が起こっているか(または何が起こるべきか)を理解できます。
すべての操作に使用されるモデルUserFormから始めます。このモデルは、ユーザーの名前とパスワード(簡略化のためにパブリックアクセス修飾子を使用しています)とユーザー名のgetterメソッドのみを保持します。そのプロパティのモックを許可するフィールド:
public class UserForm {
public String password;
public String username;
public String getUsername(){
return username;
}
}
LoginDAO をフォローしましょう。メソッドが必要な場合にのみメソッドを存在させて、必要なときにそれらをモックできるため、機能が無効になります。
public class LoginDao {
public int login(UserForm userForm){
return 0;
}
}
LoginDao は、loginメソッドのLoginServiceによって使用されます。 LoginService には、voidを返すsetCurrentUserメソッドもあります。
public class LoginService {
private LoginDao loginDao;
private String currentUser;
public boolean login(UserForm userForm) {
assert null != userForm;
int loginResults = loginDao.login(userForm);
switch (loginResults){
case 1:
return true;
default:
return false;
}
}
public void setCurrentUser(String username) {
if(null != username){
this.currentUser = username;
}
}
}
最後に、 LoginController は、loginメソッドにLoginServiceを使用します。 これには以下が含まれます:
- モックサービスへの呼び出しが行われない場合。
- 1つのメソッドのみが呼び出される場合。
- すべてのメソッドが呼び出される場合。
- 例外スローがテストされる場合。
public class LoginController {
public LoginService loginService;
public String login(UserForm userForm){
if(null == userForm){
return "ERROR";
}else{
boolean logged;
try {
logged = loginService.login(userForm);
} catch (Exception e) {
return "ERROR";
}
if(logged){
loginService.setCurrentUser(userForm.getUsername());
return "OK";
}else{
return "KO";
}
}
}
}
テストしようとしていることを確認したので、各ライブラリでどのようにモックするかを見てみましょう。
3. テスト設定
3.1. モッキート
Mockitoには、バージョン2.8.9を使用します。
モックを作成して使用する最も簡単な方法は、@Mockおよび@InjectMocksアノテーションを使用することです。 1つ目は、フィールドの定義に使用されるクラスのモックを作成し、2つ目は、作成されたモックを注釈付きのモックに挿入しようとします。
@Spy など、部分的なモック(モックされていないメソッドで通常の実装を使用するモック)を作成できる注釈がさらにあります。
そうは言っても、この「魔法」のすべてが機能するために上記のモックを使用するテストを実行する前に、 MockitoAnnotations.initMocks(this)を呼び出す必要があります。 これは通常、@Before注釈付きメソッドで実行されます。 MockitoJUnitRunnerを使用することもできます。
public class LoginControllerTest {
@Mock
private LoginDao loginDao;
@Spy
@InjectMocks
private LoginService spiedLoginService;
@Mock
private LoginService loginService;
@InjectMocks
private LoginController loginController;
@Before
public void setUp() {
loginController = new LoginController();
MockitoAnnotations.initMocks(this);
}
}
3.2. EasyMock
EasyMockには、バージョン 3.4 ( Javadoc )を使用します。 EasyMockでは、モックが「動作」を開始するには、すべてのテストメソッドで EasyMock.replay(mock)を呼び出す必要があります。そうしないと、例外が発生します。
モックとテスト済みクラスはアノテーションを介して定義することもできますが、この場合、静的メソッドを呼び出す代わりに、テストクラスにEasyMockRunnerを使用します。
モックは@Mockアノテーションで作成され、テストされたオブジェクトは @TestSubject アノテーションで作成されます(作成されたモックから依存関係が注入されます)。 テストするオブジェクトはインラインで作成する必要があります。
@RunWith(EasyMockRunner.class)
public class LoginControllerTest {
@Mock
private LoginDao loginDao;
@Mock
private LoginService loginService;
@TestSubject
private LoginController loginController = new LoginController();
}
3.3. JMockit
JMockitの場合、バージョン1.25がまだリリースされていないため(少なくともこれを書いている間)、バージョン 1.24 ( Javadoc )を使用します。
JMockitのセットアップは、部分的なモックに特定の注釈がなく(実際には必要ない)、テストランナーとして JMockit を使用する必要があることを除いて、Mockitoと同じくらい簡単です。
モックは、 @Injectable アノテーション(1つのモックインスタンスのみを作成します)または @Mocked アノテーション(注釈付きフィールドのクラスのすべてのインスタンスに対してモックを作成します)を使用して定義されます。 。
テストされたインスタンスは、 @Tested アノテーションを使用して作成されます(およびそのモックされた依存関係が挿入されます)。
@RunWith(JMockit.class)
public class LoginControllerTest {
@Injectable
private LoginDao loginDao;
@Injectable
private LoginService loginService;
@Tested
private LoginController loginController;
}
4. モックへの呼び出しがないことの確認
4.1. モッキート
モックがMockitoで呼び出しを受信しなかったことを確認するには、モックを受け入れるメソッド verifyNoInteractions()があります。
@Test
public void assertThatNoMethodHasBeenCalled() {
loginController.login(null);
Mockito.verifyNoInteractions(loginService);
}
4.2. EasyMock
モックが呼び出しを受信しなかったことを確認するには、動作を指定しないだけで、モックを再生し、最後に確認します。
@Test
public void assertThatNoMethodHasBeenCalled() {
EasyMock.replay(loginService);
loginController.login(null);
EasyMock.verify(loginService);
}
4.3. JMockit
モックが呼び出しを受信しなかったことを確認するには、そのモックの期待値を指定せず、そのモックに対して FullVerifications(mock)を実行します。
@Test
public void assertThatNoMethodHasBeenCalled() {
loginController.login(null);
new FullVerifications(loginService) {};
}
5. モックされたメソッド呼び出しの定義とモックへの呼び出しの検証
5.1. モッキート
モックメソッド呼び出しの場合、 Mockito.when(mock.method(args))。thenReturn(value)を使用できます。 ここでは、複数の呼び出しに対して異なる値を返すことができます。それらをパラメーターとして追加するだけです: thenReturn(value1、value2、value-n、…)。
この構文では、voidを返すメソッドをモックすることはできないことに注意してください。 上記の場合、上記の方法の検証を使用します(11行目に示されています)。
モックへの呼び出しの確認には、 Mockito.verify(mock).method(args)を使用できます。また、を使用してモックへの呼び出しがこれ以上行われなかったことを確認できます。 verifyNoMoreInteractions(mock)。
verifying args の場合、特定の値を渡すか、 any()、 anyString()、 anyInt()。などの事前定義されたマッチャーを使用できます。その種のマッチャーはもっとたくさんあり、次の例で見るようにマッチャーを定義する可能性さえあります。
@Test
public void assertTwoMethodsHaveBeenCalled() {
UserForm userForm = new UserForm();
userForm.username = "foo";
Mockito.when(loginService.login(userForm)).thenReturn(true);
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
Mockito.verify(loginService).login(userForm);
Mockito.verify(loginService).setCurrentUser("foo");
}
@Test
public void assertOnlyOneMethodHasBeenCalled() {
UserForm userForm = new UserForm();
userForm.username = "foo";
Mockito.when(loginService.login(userForm)).thenReturn(false);
String login = loginController.login(userForm);
Assert.assertEquals("KO", login);
Mockito.verify(loginService).login(userForm);
Mockito.verifyNoMoreInteractions(loginService);
}
5.2. EasyMock
モックメソッド呼び出しには、 EasyMock.expect(mock.method(args))。andReturn(value)を使用します。
モックへの呼び出しの確認には、 EasyMock .verify(mock)を使用できますが、がを呼び出した後は、常にと呼ぶ必要があります。 X144X] EasyMock.replay(mock)。
verifying args の場合、特定の値を渡すか、isA (Class.class)、 anyString()、 anyInt( )、およびその種類のマッチャーのさらに多くの、そして再びあなたのマッチャーを定義する可能性。
@Test
public void assertTwoMethodsHaveBeenCalled() {
UserForm userForm = new UserForm();
userForm.username = "foo";
EasyMock.expect(loginService.login(userForm)).andReturn(true);
loginService.setCurrentUser("foo");
EasyMock.replay(loginService);
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
EasyMock.verify(loginService);
}
@Test
public void assertOnlyOneMethodHasBeenCalled() {
UserForm userForm = new UserForm();
userForm.username = "foo";
EasyMock.expect(loginService.login(userForm)).andReturn(false);
EasyMock.replay(loginService);
String login = loginController.login(userForm);
Assert.assertEquals("KO", login);
EasyMock.verify(loginService);
}
5.3. JMockit
JMockitを使用して、テスト用のステップを定義しました:記録、再生、および検証。
RecordはnewExpectations(){{}} ブロック(複数のモックのアクションを定義できます)で実行され、replayは呼び出すだけで実行されますテストされたクラスのメソッド(モックオブジェクトを呼び出す必要があります)、および verification は、新しい Verifications(){{}} ブロック(このブロックに検証を定義できます)内で実行されますいくつかのモック)。
モックメソッド呼び出しの場合、 mock.method(args);を使用できます。 結果=値;Expectationsブロック内の。 ここでは、 result = value;の代わりにreturns(value1、value2、…、valuen); を使用するだけで、複数の呼び出しに対して異なる値を返すことができます。
モックへの呼び出しの検証には、新しい検証(){{mock.call(value)}} または新しい検証(モック){{}}を使用できます。 ]以前に定義されたすべての予想される呼び出しを検証します。
verifying args の場合、特定の値を渡すか、 any 、 anyString 、anyLongのような事前定義値を使用できます。 ]、そしてその種の特別な値の多くと、あなたのマッチャー(ハムクレストマッチャーでなければならない)を定義する可能性もあります。
@Test
public void assertTwoMethodsHaveBeenCalled() {
UserForm userForm = new UserForm();
userForm.username = "foo";
new Expectations() {{
loginService.login(userForm); result = true;
loginService.setCurrentUser("foo");
}};
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
new FullVerifications(loginService) {};
}
@Test
public void assertOnlyOneMethodHasBeenCalled() {
UserForm userForm = new UserForm();
userForm.username = "foo";
new Expectations() {{
loginService.login(userForm); result = false;
// no expectation for setCurrentUser
}};
String login = loginController.login(userForm);
Assert.assertEquals("KO", login);
new FullVerifications(loginService) {};
}
6. 例外スローをあざける
6.1. モッキート
例外スローは、 Mockito.when(mock.method(args))の後に .thenThrow(ExceptionClass.class)を使用してモックできます。
@Test
public void mockExceptionThrowing() {
UserForm userForm = new UserForm();
Mockito.when(loginService.login(userForm)).thenThrow(IllegalArgumentException.class);
String login = loginController.login(userForm);
Assert.assertEquals("ERROR", login);
Mockito.verify(loginService).login(userForm);
Mockito.verifyNoInteractions(loginService);
}
6.2. EasyMock
例外スローは、 EasyMock.expect(…)呼び出しの後に .andThrow(new ExceptionClass())を使用してモックできます。
@Test
public void mockExceptionThrowing() {
UserForm userForm = new UserForm();
EasyMock.expect(loginService.login(userForm)).andThrow(new IllegalArgumentException());
EasyMock.replay(loginService);
String login = loginController.login(userForm);
Assert.assertEquals("ERROR", login);
EasyMock.verify(loginService);
}
6.3. JMockit
JMockitoを使用したモック例外スローは特に簡単です。 「通常の」戻り値ではなく、モックされたメソッド呼び出しの結果として例外を返すだけです。
@Test
public void mockExceptionThrowing() {
UserForm userForm = new UserForm();
new Expectations() {{
loginService.login(userForm); result = new IllegalArgumentException();
// no expectation for setCurrentUser
}};
String login = loginController.login(userForm);
Assert.assertEquals("ERROR", login);
new FullVerifications(loginService) {};
}
7. 渡すオブジェクトをあざける
7.1. モッキート
メソッド呼び出しの引数として渡すモックを作成することもできます。 Mockitoを使用すると、ワンライナーでそれを行うことができます。
@Test
public void mockAnObjectToPassAround() {
UserForm userForm = Mockito.when(Mockito.mock(UserForm.class).getUsername())
.thenReturn("foo").getMock();
Mockito.when(loginService.login(userForm)).thenReturn(true);
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
Mockito.verify(loginService).login(userForm);
Mockito.verify(loginService).setCurrentUser("foo");
}
7.2. EasyMock
モックはEasyMock.mock(Class.class)とインラインで作成できます。 その後、 EasyMock.expect(mock.method())を使用して実行の準備をすることができます。使用する前に、必ず EasyMock.replay(mock)を呼び出すことを忘れないでください。
@Test
public void mockAnObjectToPassAround() {
UserForm userForm = EasyMock.mock(UserForm.class);
EasyMock.expect(userForm.getUsername()).andReturn("foo");
EasyMock.expect(loginService.login(userForm)).andReturn(true);
loginService.setCurrentUser("foo");
EasyMock.replay(userForm);
EasyMock.replay(loginService);
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
EasyMock.verify(userForm);
EasyMock.verify(loginService);
}
7.3. JMockit
1つのメソッドのオブジェクトをモックするには、モックされたオブジェクトをパラメーターとしてテストメソッドに渡すだけです。 次に、他のモックと同じように期待を作成できます。
@Test
public void mockAnObjectToPassAround(@Mocked UserForm userForm) {
new Expectations() {{
userForm.getUsername(); result = "foo";
loginService.login(userForm); result = true;
loginService.setCurrentUser("foo");
}};
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
new FullVerifications(loginService) {};
new FullVerifications(userForm) {};
}
8. カスタム引数マッチング
8.1. モッキート
場合によっては、モックされた呼び出しの引数の照合は、固定値または anyString()よりも少し複雑にする必要があります。 その場合、Mockitoには、で使用されるマッチャークラスがあります。 argThat(ArgumentMatcher <>) 。
@Test
public void argumentMatching() {
UserForm userForm = new UserForm();
userForm.username = "foo";
// default matcher
Mockito.when(loginService.login(Mockito.any(UserForm.class))).thenReturn(true);
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
Mockito.verify(loginService).login(userForm);
// complex matcher
Mockito.verify(loginService).setCurrentUser(ArgumentMatchers.argThat(
new ArgumentMatcher<String>() {
@Override
public boolean matches(String argument) {
return argument.startsWith("foo");
}
}
));
}
8.2. EasyMock
EasyMockでは、実際のマッチャーを作成してから EasyMock.reportMatcher(IArgumentMatcher)でレポートする静的メソッドを作成する必要があるため、カスタム引数のマッチングは少し複雑です。
このメソッドが作成されたら、(行の例に示されているように)メソッドを呼び出してモック期待値で使用します。
@Test
public void argumentMatching() {
UserForm userForm = new UserForm();
userForm.username = "foo";
// default matcher
EasyMock.expect(loginService.login(EasyMock.isA(UserForm.class))).andReturn(true);
// complex matcher
loginService.setCurrentUser(specificArgumentMatching("foo"));
EasyMock.replay(loginService);
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
EasyMock.verify(loginService);
}
private static String specificArgumentMatching(String expected) {
EasyMock.reportMatcher(new IArgumentMatcher() {
@Override
public boolean matches(Object argument) {
return argument instanceof String
&& ((String) argument).startsWith(expected);
}
@Override
public void appendTo(StringBuffer buffer) {
//NOOP
}
});
return null;
}
8.3. JMockit
JMockitとのカスタム引数の照合は、特別な withArgThat(Matcher)メソッド( HamcrestのMatcher オブジェクトを受け取る)を使用して行われます。
@Test
public void argumentMatching() {
UserForm userForm = new UserForm();
userForm.username = "foo";
// default matcher
new Expectations() {{
loginService.login((UserForm) any);
result = true;
// complex matcher
loginService.setCurrentUser(withArgThat(new BaseMatcher<String>() {
@Override
public boolean matches(Object item) {
return item instanceof String && ((String) item).startsWith("foo");
}
@Override
public void describeTo(Description description) {
//NOOP
}
}));
}};
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
new FullVerifications(loginService) {};
}
9. 部分的なモッキング
9.1. モッキート
Mockitoは、2つの方法で部分的なモック(一部のメソッドでモックされたメソッド呼び出しの代わりに実際の実装を使用するモック)を許可します。
通常のモックメソッド呼び出し定義で.thenCallRealMethod()を使用するか、モックの代わりに spy を作成できます。この場合、そのデフォルトの動作は次のようになります。モックされていないすべてのメソッドでの実際の実装。
@Test
public void partialMocking() {
// use partial mock
loginController.loginService = spiedLoginService;
UserForm userForm = new UserForm();
userForm.username = "foo";
// let service's login use implementation so let's mock DAO call
Mockito.when(loginDao.login(userForm)).thenReturn(1);
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
// verify mocked call
Mockito.verify(spiedLoginService).setCurrentUser("foo");
}
9.2. EasyMock
EasyMockでは、モックを作成するときにどのメソッドをモックするかを定義する必要があるため、部分的なモックも少し複雑になります。
これは、 EasyMock.partialMockBuilder(Class.class).addMockedMethod( “methodName”)。createMock()を使用して実行されます。 これが完了すると、他の非部分的なモックと同じようにモックを使用できます。
@Test
public void partialMocking() {
UserForm userForm = new UserForm();
userForm.username = "foo";
// use partial mock
LoginService loginServicePartial = EasyMock.partialMockBuilder(LoginService.class)
.addMockedMethod("setCurrentUser").createMock();
loginServicePartial.setCurrentUser("foo");
// let service's login use implementation so let's mock DAO call
EasyMock.expect(loginDao.login(userForm)).andReturn(1);
loginServicePartial.setLoginDao(loginDao);
loginController.loginService = loginServicePartial;
EasyMock.replay(loginDao);
EasyMock.replay(loginServicePartial);
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
// verify mocked call
EasyMock.verify(loginServicePartial);
EasyMock.verify(loginDao);
}
9.3. JMockit
JMockitによる部分的なモックは特に簡単です。 Expectations(){{}} でモック動作が定義されていないすべてのメソッド呼び出しは、「実際の」実装を使用します。
ここで、 login()メソッドの実際の実装を使用しながら、 LoginServiceクラスを部分的にモックしてsetCurrentUser()メソッドをモックしたいとします。
これを行うには、最初にLoginServiceのインスタンスを作成してexpectationsブロックに渡します。 次に、 setCurrentUser()メソッドの期待値のみを記録します。
@Test
public void partialMocking() {
LoginService partialLoginService = new LoginService();
partialLoginService.setLoginDao(loginDao);
loginController.loginService = partialLoginService;
UserForm userForm = new UserForm();
userForm.username = "foo";
new Expectations(partialLoginService) {{
// let's mock DAO call
loginDao.login(userForm); result = 1;
// no expectation for login method so that real implementation is used
// mock setCurrentUser call
partialLoginService.setCurrentUser("foo");
}};
String login = loginController.login(userForm);
Assert.assertEquals("OK", login);
// verify mocked call
new Verifications() {{
partialLoginService.setCurrentUser("foo");
}};
}
10. 結論
この投稿では、3つのJavaモックライブラリを比較してきました。それぞれに長所と短所があります。
- 3つすべてが簡単に構成され、モックとテスト対象オブジェクトを定義するのに役立つ注釈が付けられ、ランナーがモックインジェクションを可能な限り無痛にすることができます。
- Mockitoは、部分的なモック用の特別な注釈があるため、ここで勝つと思いますが、JMockitはそれを必要としないので、この2つを結び付けているとしましょう。
- 3つすべてが多かれ少なかれrecord-replay-verifyパターンに従いますが、私たちの意見では、ブロックでそれらを使用することを強制するJMockitであるため、テストはより構造化されます。
- 使いやすさは重要であるため、テストを定義するための作業をできるだけ少なくすることができます。 JMockitは、常に同じ構造に固定されているために選択されるオプションになります。
- Mockitoは多かれ少なかれ最もよく知られているので、コミュニティはより大きくなります。
- モックを使用するたびにreplayを呼び出さなければならないのは明らかなノーゴーなので、EasyMockにはマイナス1を付けます。
- 一貫性/シンプルさも私にとって重要です。 「通常の」結果でも例外の場合と同じJMockitの結果を返す方法が気に入りました。
そうは言っても、これまで Mockito を使用していたにもかかわらず、勝者の一種としてJMockitを選択します。シンプルで固定された構造で、これから使ってみます。
このチュートリアルの完全な実装はGitHubプロジェクトにありますので、ダウンロードして試してみてください。