mockito チュートリアル
mockitoを使い始める
サーチ…
備考
MockitoはシンプルなAPIを使用して読みやすい単体テストを書く能力を提供することを目指すJava Mockingフレームワークです。他のフレームワークが使用するexpect-run-verifyパターンを残すことによって、他のモッキングフレームワークとは異なります。
代わりに、(非最終的な)クラスとインタフェースを模擬する1つの方法しか知らず、柔軟な引数マッチャーに基づいて検証とスタブを行うことができます。
現在のバージョン1.10.19は、
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
</dependency>
またはグラデル
repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:1.+" }
バージョン2はまだベータ版です。
バージョン
Mockitoを使った簡単な単体テスト
テストするクラスは次のとおりです。
public class Service {
private Collaborator collaborator;
public Service(Collaborator collaborator) {
this.collaborator = collaborator;
}
public String performService(String input) {
return collaborator.transformString(input);
}
}
その協力者は:
public class Collaborator {
public String transformString(String input) {
return doStuff();
}
private String doStuff() {
// This method may be full of bugs
. . .
return someString;
}
}
私たちのテストでは、 Collaborator
とそのバグの依存関係を解消したいので、 Collaborator
を模倣しようCollaborator
ます:
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
public class ServiceTest {
@Test
public void testPerformService() throws Exception {
// Configure mock
Collaborator collaboratorMock = mock(Collaborator.class);
doReturn("output").when(collaboratorMock).transformString("input");
// Perform the test
Service service = new Service(collaboratorMock);
String actual = service.performService("input");
// Junit asserts
String expected = "output";
assertEquals(expected, actual);
}
}
Mockitoアノテーションの使用
テストするクラスは次のとおりです。
public class Service{
private Collaborator collaborator;
public Service(Collaborator collaborator){
this.collaborator = collaborator;
}
public String performService(String input){
return collaborator.transformString(input);
}
}
その協力者は:
public class Collaborator {
public String transformString(String input){
return doStuff();
}
private String doStuff()
{
// This method may be full of bugs
. . .
return someString;
}
}
私たちのテストでは、 Collaborator
とそのバグの依存関係を解除したいので、 Collaborator
を模倣しようCollaborator
ます。 @Mock
アノテーションを使用すると、テストごとにさまざまなモックのインスタンスを作成する便利な方法です。
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.InjectMocks;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ServiceTest {
@Mock
private Collaborator collaboratorMock;
@InjectMocks
private Service service;
@Test
public void testPerformService() throws Exception {
// Configure mock
doReturn("output").when(collaboratorMock).transformString("input");
// Perform the test
String actual = service.performService("input");
// Junit asserts
String expected = "output";
assertEquals(expected, actual);
}
@Test(expected=Exception.class)
public void testPerformServiceShouldFail() throws Exception {
// Configure mock
doThrow(new Exception()).when(collaboratorMock).transformString("input");
// Perform the test
service.performService("input");
}
}
Mockitoは依存性注入を次の順序で解決しようと試みます:
- コンストラクタベースの注入モックは、ほとんどの引数を使ってコンストラクタに注入されます(引数が見つからない場合はnullが渡されます)。オブジェクトがコンストラクタを介して正常に作成された場合、他の戦略は適用されません。
- セッターベースのインジェクションモックはタイプ別に注入されます。同じタイプのプロパティが複数ある場合は、プロパティ名とモック名が一致します。
- 直接フィールド注入 - セッターベース注入と同じ。
前述の戦略のいずれかが失敗した場合、失敗は報告されないことに注意してください。
最新バージョンのMockitoでは、このメカニズムの詳細については、最新の@InjectMocks
を参照してください。
インストールとセットアップ
インストール
Mockitoをインストールする好ましい方法は、選択したビルドシステムでmockito-core
依存することを宣言することです。 2016年7月22日現在、最新の非ベータ版は1.10.19ですが、 2.xは既に移行されることが推奨されています 。
Maven
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
受け台
repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:1.+" }
Mockito自体に加えて、HamcrestとObjenesisを含むmockito-all
もあります。主にAntユーザのためにMavenを介して配布されていますが、Mockito 2.xでは配布が中止されています。
インポート
Mockito施設のほとんどは、静的メソッドですorg.mockito.Mockito
。したがって、Mockitoはこのようにしてクラスに静的にインポートできます:
import static org.mockito.Mockito.*;
ドキュメントエントリポイントは、このクラスのjavadocにあります。
オブジェクトのいくつかのメソッドをモックする
オブジェクトのいくつかのメソッドは、mockitoのspy()
を使って嘲笑されます。
たとえば、メソッドクラスが動作するにはいくつかのWebサービスが必要であるとします。
public class UserManager {
List<User> users;
public UserManager() {
user = new LinkedLisk<User>();
}
public void addUser(User user) {
if (isValid(user)) {
user.add(user);
} else {
throw new NotValidUserException();
}
}
protected boolean isValid(User user) {
//some online web service to check if user is valid
}
public int numberOfUsers() {
return users.size();
}
}
addUser
メソッドは、 UserManager
便利なテストを行うためにテストする必要があります。しかし、ここでは依存関係が見つかり、 isValid
はコードに含まれていない外部Webサービスが必要です。次に、この外部依存関係を中和する必要があります。
この場合、 isValid
をモックするだけで、残りのUserManager
メソッドをテストすることができます。
@Test
public void testAddUser() {
User user = mock(User.class);
UserManager manager = spy(new UserManager());
//it forces to manager.isValid to return true
doReturn(true).when(manager).isValid(anyObject());
manager.addUser(user);
assertTrue(manager.numberOfUsers(), 1);
}
user
が有効でないシナリオを簡単に確認できます。
@Test(expectedExceptions = NotValidUserException.class)
public void testNotValidAddUser() {
User user = mock(User.class);
UserManager manager = spy(new UserManager());
//it forces to manager.isValid to return false
doReturn(false).when(manager).isValid(anyObject());
manager.addUser(user);
}
シンプルな最小のモッキート試験
この例は、嘲笑されたArrayList
を使った最小のMockitoテストを示しています:
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class MockitoTest
{
@Mock
ArrayList<String> listMock;
@Test
public void testAppend() {
// configure the mock to return "foobar" whenever "get()"
// is called on "listMock" with an int value as parameter
doReturn("foobar").when(listMock).get(anyInt());
String result = listMock.get(0);
assertEquals("foobar", result);
}
}
ArgumentCaptorによる引数の検証
モックで呼び出されたメソッドの引数を検証するには、 ArgumentCaptor
クラスを使用します。これにより、引数をあなたのテストメソッドに抽出し、そのメソッドに対してアサーションを実行することができます。
この例では、指定されたIDを持つユーザーの名前を更新するメソッドをテストします。このメソッドはユーザーを読み込み、 name
属性を指定された値で更新し、後で保存します。このテストでは、 save
メソッドに渡された引数が、正しいIDと名前を持つUser
オブジェクトであることを確認する必要があります。
// This is mocked in the test
interface UserDao {
void save(User user);
}
@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
@Mock
UserDao userDao;
@Test
public void testSetNameForUser() {
UserService serviceUnderTest = new UserService(userDao);
serviceUnderTest.setNameForUser(1L, "John");
ArgumentCaptor<User> userArgumentCaptor = ArgumentCaptor.forClass(User.class);
verify(userDao).save(userArgumentCaptor.capture());
User savedUser = userArgumentCaptor.getValue();
assertTrue(savedUser.getId() == 1);
assertTrue(savedUser.getName().equals("John"));
}
}
ArgumentMatcherによる引数の検証
MockitoはArgumentMatcher<T>
を検証するための抽象ArgumentMatcher<T>
クラスとともにMatcher<T>
インタフェースを提供します。これは、 ArgumentCaptor
と同じユースケースに対して異なるアプローチを使用します。さらに、ArgumentMatcherはモックにも使用できます。どちらのユースケースも、合理的に読みやすいテストコードを提供するMockito.argThat()
メソッドを使用します。
verify(someMock).someMethod(Mockito.argThat(new ArgumentMatcher<String>() {
@Override
public boolean matches(Object o) {
return o instanceof String && !((String)o).isEmpty();
}
});
ArgumentMatcherのJavaDocsから:
警告:複雑な引数マッチング、特にカスタム引数マッチャーを使用することで合理的であること。テストが読みにくくなる可能性があるためです。時々、モックに渡される引数にequals()を実装するほうが良いでしょう(Mockitoは引数マッチングのために自然にequals()を使います)。これは、テストクリーナーを作ることができます。
Mockitoでモックされたオブジェクトを作成する
Mockitoでオブジェクトをモックするには、2つの方法があります。
- アノテーションを介して
- モック関数を介して
アノテーションを使用:
JUnitテストランナー:
@RunWith(MockitoJUnitRunner.class)
public class FooTest {
@Mock
private Bar barMock;
// ...
}
また、 MockitoJUnitRunner
と同じ機能を提供するMockitoのJUnit @Rule
使うこともできますが、 @RunWith
テストランナーは必要ありません。
public class FooTest {
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
@Mock
private Bar barMock;
// ...
}
@RunWith
や@Rule
アノテーションを使うことができない場合は、 "手札"を初期化することもできます:
public class FooTest {
@Mock
private Bar barMock;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
// ...
}
モック機能を介して:
public class FooTest {
private Bar barMock = Mockito.mock(Bar.class);
// ...
}
型の消去のため、上記のようにジェネリッククラスをモックすることはできません。基本クラスをモックし、明示的に適切なジェネリック型にキャストする必要があります:
public class FooTest {
private Bar<String> genericBarMock = (Bar<String>) Mockito.mock(Bar.class);
// ...
}
モックされたオブジェクトにビヘイビアを追加する
Mockito.when(mock.returnSomething()).thenReturn("my val");
mock.returnSomething(); // returns "my val"
mock.returnSomething(); // returns "my val" again
mock.returnSomething(); // returns "my val" again and again and again...
2番目の呼び出しで異なる値が必要な場合は、必要な戻り引数をthenReturnメソッドに追加できます。
Mockito.when(mock.returnSomething()).thenReturn("my val", "other val");
mock.returnSomething(); // returns "my val"
mock.returnSomething(); // returns "other val"
mock.returnSomething(); // returns "other val" again
モックに動作を追加せずにメソッドを呼び出すと、nullが返されます:
barMock.mock.returnSomethingElse(); // returns null
モックされたメソッドにパラメータがある場合は、値も宣言する必要があります。
Mockito.when(mock.returnSomething("param 1")).thenReturn("my val 1");
Mockito.when(mock.returnSomething("param 2")).thenReturn("my val 2");
mock.returnSomething("param 1"); // returns "my val 1"
mock.returnSomething("param 2"); // returns "my val 2"
mock.returnSomething("param 3"); // returns null
param値を気にしない場合、Matchers.any()を使用できます:
Mockito.when(mock.returnSomething(Matchers.any())).thenReturn("p1");
mock.returnSomething("param 1"); // returns "p1"
mock.returnSomething("param other"); // returns "p1"
例外をスローするには、次のメソッドを使用します。
Mockito.when(mock.returnSomething()).thenThrow(new Exception());
mock.returnSomething(); // throws Exception
モックに渡された引数をチェックする
このクラスがあると仮定し、 doSmth
メソッドをテストしたいと思います。この場合、パラメータ "val"がfoo
渡されているかどうかを確認する必要があります。オブジェクトfoo
は嘲笑されます。
public class Bar {
private final Foo foo;
public Bar(final Foo foo) {
this.foo = foo;
}
public void doSmth() {
foo.bla("val");
}
}
ArgumentCaptor
これを実現できます:
@Mock
private Foo fooMock;
@InjectMocks
private Bar underTest;
@Captor
private ArgumentCaptor<String> stringCaptor;
@Test
public void should_test_smth() {
underTest.doSmth();
Mockito.verify(fooMock).bla(stringCaptor.capture());
assertThat(stringCaptor.getValue(), is("val"));
}
モックされたオブジェクトのメソッド呼び出しを確認する
モックされたオブジェクトでメソッドが呼び出されたかどうかを確認するには、 Mockito.verify
メソッドを使用できます。
Mockito.verify(someMock).bla();
この例では、メソッドbla
がsomeMock
モックオブジェクトで呼び出されたと主張します。
特定のパラメータでメソッドが呼び出されたかどうかを確認することもできます。
Mockito.verify(someMock).bla("param 1");
あなたはメソッドが呼び出されなかったことを確認したい場合は、追加渡すことができVerificationMode
ためのパラメータverify
:
Mockito.verify(someMock, Mockito.times(0)).bla();
これは、このメソッドが複数回呼び出されたことを確認したい場合にも機能します(この場合、メソッドbla
が23回呼び出されたことを確認します)。
Mockito.verify(someMock, Mockito.times(23)).bla();
これらはVerificationMode
パラメータのより多くの例であり、メソッドの呼び出し回数をより詳細に制御できます。
Mockito.verify(someMock, Mockito.never()).bla(); // same as Mockito.times(0)
Mockito.verify(someMock, Mockito.atLeast(3)).bla(); // min 3 calls
Mockito.verify(someMock, Mockito.atLeastOnce()).bla(); // same as Mockito.atLeast(1)
Mockito.verify(someMock, Mockito.atMost(3)).bla(); // max 3 calls
スタッビングボイドメソッド
void
メソッドは、 doThrow() 、 doAnswer() 、 doNothing() 、 doCallRealMethod()の一連のメソッドを使用してスタブすることができます。
Runnable mock = mock(Runnable.class);
doThrow(new UnsupportedOperationException()).when(mock).run();
mock.run(); // throws the UnsupportedOperationException
ことに注意してくださいvoid
の方法が使用してスタブすることはできませんwhen(..)
、コンパイラは好きではない原因void
引数としてメソッドを。