SoftwareEngineering/Java/UnitTest/JMockit 前書き †このチュートリアルでは、サンプル・テスト(Java 8を使用)の助けを借りて、ライブラリーで使用可能なAPIを調べます。 このチュートリアルはかなり完成していますが、公開されたAPI全体を詳しくカバーしようとはしません。 別の章でコードカバレッジツールについて説明します。 自動化された開発者テストとテスト分離 †自動化された開発者テストは、開発者自身が独自のコードをテストするために作成したテストです。 自動化された開発者テストは、個々のプログラム「ユニット」、複数のそのようなユニットが一緒に働くかどうか、またはテスト中のシステムの「スライス」全体(「SUT」)の2つの大きなカテゴリーに分けられます。
統合テストには複数のユニット間のやりとりが含まれていますが、特定のテストでは、関連するすべてのコンポーネント、レイヤー、またはサブシステムの実行には関心がない場合があります。
モックオブジェクトによるテスト †孤立してコードをテストするための一般的で強力な技術は、"モック"の使用です。 JMockit は、メソッドやコンストラクタを "実際の"(モックではない)クラスに直接偽装し、テストでモックオブジェクトをインスタンス化してテスト中のコードに渡す必要がなくなり、従来のモックオブジェクトを超えています。 代わりに、テスト対象のコードによって作成されたオブジェクトは、実際のクラスでメソッドまたはコンストラクタが呼び出されるたびに、テストで定義されたモックの動作を実行します。 クラスが嘲笑されたとき、既存のメソッド/コンストラクタの元の実装は、通常、単一のテストの期間、模擬実装に一時的に置き換えられます。 このモーキングのアプローチは、 publicインスタンス・メソッドだけでなく、 finalメソッドとstaticメソッド、およびコンストラクタにも適用されます。 モックは独立した単体テストで最も有用ですが、統合テストでも使用できます。 たとえば、ある時点で電子メールを送信するビジネス操作をテストすることができます。 電子メールが正しく送信されたことを確認するために、このテストでは、電子メール送信APIを模擬し、他のすべてのコンポーネントで実際のコードを実行することもできます(代わりに、偽の電子メールサーバーを設定することもできますテストの最後にアサーションで相談してください)。 例 †次の手順でビジネスオペレーションを提供するビジネスサービスクラスを検討してください。
最初の2つの手順では、アプリケーションデータベースへのアクセスが必要です。 したがって、サービスクラスには、永続性と電子メールの2つの依存関係があります。 package tutorial.domain; import java.math.*; import java.util.*; import org.apache.commons.mail.*; import static tutorial.persistence.Database.*; public final class MyBusinessService { private final EntityX data; public MyBusinessService(EntityX data) { this.data = data; } public void doBusinessOperationXyz() throws EmailException { List<EntityX> items = (1) find("select item from EntityX item where item.someProperty = ?1", data.getSomeProperty()); // Compute or obtain from another service a total value for the new persistent entity: BigDecimal total = ... data.setTotal(total); (2) persist(data); sendNotificationEmail(items); } private void sendNotificationEmail(List<EntityX> items) throws EmailException { Email email = new SimpleEmail(); email.setSubject("Notification about processing of ..."); (3) email.addTo(data.getCustomerEmail()); // Other e-mail parameters, such as the host name of the mail server, have defaults defined // through external configuration. String message = buildNotificationMessage(items); email.setMsg(message); (4) email.send(); } private String buildNotificationMessage(List<EntityX> items) { ... } } Database クラスには静的メソッドとプライベートコンストラクタのみが含まれています。 では、既存のアプリケーションコードを変更せずに"doBusinessOperationXyz"メソッドをどのようにテストできますか? package tutorial.domain; import org.apache.commons.mail.*; import static tutorial.persistence.Database.*; import org.junit.*; import org.junit.rules.*; import static org.junit.Assert.*; import mockit.*; public final class MyBusinessServiceTest { @Rule public final ExpectedException thrown = ExpectedException.none(); @Tested final EntityX data = new EntityX(1, "abc", "someone@somewhere.com"); @Tested(fullyInitialized = true) MyBusinessService businessService; @Mocked SimpleEmail anyEmail; @Test public void doBusinessOperationXyz() throws Exception { EntityX existingItem = new EntityX(1, "AX5", "abc@xpta.net"); (1) persist(existingItem); businessService.doBusinessOperationXyz(); (2) assertNotEquals(0, data.getId()); // implies "data" was persisted (4) new Verifications() {{ anyEmail.send(); times = 1; }}; } @Test public void doBusinessOperationXyzWithInvalidEmailAddress() throws Exception { String email = "invalid address"; data.setCustomerEmail(email); (3) new Expectations() {{ anyEmail.addTo(email); result = new EmailException(); }}; thrown.expect(EmailException.class); businessService.doBusinessOperationXyz(); } } サンプルのテストでは、JMockit APIの2つのアノテーションを使用しています。 @Testedは、テスト対象のオブジェクトを適切に初期設定しますが、 @Mockedは与えられた型に@Mocked適用します。 テストにも示されているように、 new Expectations() {{ ... }}ブロック内での記録とnew Verifications() {{ ... }} block内でのnew Verifications() {{ ... }} block )は、録音ブロックまたは検証ブロックの中から希望のメソッド(ここでは示されていなくてもコンストラクタと同様)を呼び出します。 JMockitによるテストの実行 †JMockit APIを使用するテストを実行するには、通常どおり Java IDE、Maven / Gradle / Ant ビルドスクリプトなどを使用します。
他の状況(Oracle JDK以外のJDK実装で実行する場合など)では、JVM初期化パラメータとして " -javaagent: <proper path> /jmockit-1.x.jar "を渡す必要があります。 これは、EclipseとIntelliJ IDEA、またはMaven、Gradle、Antなどのビルドツールを使用して、「Run / Debug Configuration」で実行できます。 Mavenからのテストの実行 †JMockit成果物は中央のMavenリポジトリにあります。 これらをテストスイートで使用するには、 pom.xmlファイルに次の行を追加します。 <dependencies> <dependency> <groupId>org.jmockit</groupId> <artifactId>jmockit</artifactId> <version>1.x</version> <scope>test</scope> </dependency> </dependencies> 指定したバージョンが実際に必要なバージョンであることを確認してください。 開発履歴ページで現在のバージョンを探します。 JUnit 4を使用する場合、この依存関係は " junit "依存関係の前に来る必要があります。 Maven で JMockit Coverage を使用する方法については、その章の該当するセクションを参照してください。 Gradleからのテストの実行 †GradleはmavenCentral()リポジトリから必要な成果物をダウンロードします。 gradle.buildファイルでは、 jmockit依存関係(JUnit 4.xを使用している場合はjunit依存関係の前にあることが望ましい)を追加し、 " x "を目的のバージョン番号に置き換えます。 dependencies { ... "compile" dependencies ... testCompile 'org.jmockit:jmockit:1.x' }
JUnit Antタスクによるテストの実行 †build.xmlスクリプトで<junit>要素を使用する場合は、別のJVMインスタンスを使用することが重要です。 たとえば、次のようなものがあります。 <junit fork="yes" forkmode="once" dir="directoryContainingJars"> <classpath path="jmockit-1.x.jar"/> <!-- Additional classpath entries, including the appropriate junit.jar --> <batchtest> <!-- filesets specifying the desired test classes --> </batchtest> </junit> |