JMockit An automated testing toolkit for Java

Introduction

  1. Automated developer testing and test isolation
    開発者のテストの自動化とテストの分離
  2. Testing with mock objects
    モックオブジェクトを使ったテスト
  3. An example

  1. Running tests with JMockit
    JMockit でテストを実行する
    1. Running tests from Maven
      Mavenからのテストの実行
    2. Running tests from Gradle
      Gradleからテストを実行する

The toolkit is provided as a set of artifacts deployed to the Maven Central repository.
ツールキットは、Maven Central リポジトリにデプロイされた成果物のセットとして提供されます。
It requires Java 7 or newer for test execution; tests must use JUnit or TestNG.
テストの実行には Java 7 以降が必要です。テストでは JUnit または TestNG を使用する必要があります。
For instructions on how to add the library to a Java project, see Running tests with JMockit.
ライブラリを Java プロジェクトに追加する方法の詳細については、「JMockit を使用したテストの実行」を参照してください。

In this tutorial we examine the APIs available in the library, with the help of example tests (using Java 8).
このチュートリアルでは、サンプル テスト (Java 8 を使用) を使用して、ライブラリで使用可能な API を調べます。
The central API - a single annotation - provides support for the automatic instantiation and initialization of the objects to be tested.
中央 API (単一のアノテーション) は、テスト対象のオブジェクトの自動インスタンス化と初期化をサポートします。
Then we have the mocking API (also known as the "Expectations" API), intended for tests which use mocked dependencies.
次に、モックされた依存関係を使用するテストを目的としたモック API (「Expectations」API とも呼ばれます) があります。
Finally, there is a small faking API (aka the "Mockups" API), which can be used for the creation and application of fake implementations that avoid the full cost of external components.
最後に、外部コンポーネントのコスト全体を回避する偽の実装の作成と適用に使用できる、小さな偽造 API (別名「Mockups」API) があります。

Even though the tutorial is fairly complete, it does not attempt to cover the entire published APIs in detail.
チュートリアルはかなり完全ですが、公開されている API 全体を詳細に説明しようとしているわけではありません。
A complete and detailed specification for all annotations, classes, methods, etc. is provided through the API documentation.
すべてのアノテーション、クラス、メソッドなどの完全かつ詳細な仕様は、API ドキュメントを通じて提供されます。
The "jmockit-1.x-sources.jar" library file (downloadable from the Maven Central repository), contains Java source files (with Javadoc comments) for easy access to the API source code and documentation from a Java IDE.
「jmockit-1.x-sources.jar」ライブラリ ファイル (Maven Central リポジトリからダウンロード可能) には、Java IDE から API ソース コードとドキュメントに簡単にアクセスできるようにするための Java ソース ファイル (Javadoc コメント付き) が含まれています。

A separate chapter covers the code coverage tool.
コード カバレッジ ツールについては別の章で説明します。

1 Automated developer testing and test isolation
1 開発者のテストの自動化とテストの分離

Automated developer tests are those written by the developers themselves, to test their own code.
自動化された開発者テストは、開発者自身が自分のコードをテストするために作成したテストです。
They are usually written with the help of a testing framework, such as JUnit or TestNG; JMockit supports both.
これらは通常、JUnit や TestNG などのテスト フレームワークを使用して記述されます。JMockit は両方をサポートしています。

Automated developer tests can be divided in two broad categories, whether they target individual program "units", multiple such units working together, or an entire "slice" of the system under test (the "SUT").
自動化された開発者テストは、個々のプログラム「ユニット」を対象とするか、連携して動作する複数のユニットを対象とするか、テスト対象システムの「スライス」(「SUT」) 全体を対象とするかによって、大きく 2 つのカテゴリに分けられます。

  1. Unit tests, intended to test a class or component in isolation from the rest of the system.
    ユニット テストは、システムの他の部分から分離してクラスまたはコンポーネントをテストすることを目的としています。
  2. Integration tests, intended to test system operations that encompass a unit and its dependencies (other classes/components with which the unit under test interacts).
    統合テストは、ユニットとその依存関係 (テスト対象のユニットが対話する他のクラス/コンポーネント) を含むシステム操作をテストすることを目的としています。
    Such tests range from end-to-end system tests which run through the application's UI (when the SUT has one), to tests that exercise a small set of inter-related units.
    このようなテストは、アプリケーションの UI (SUT に UI がある場合) を介して実行されるエンドツーエンドのシステム テストから、相互に関連する少数のユニットを実行するテストまで多岐にわたります。
    Here, we are particularly interested in subcutaneous tests, which are not executed through the application UI, but otherwise exercise all the program units involved in a meaningful business scenario.
    ここでは、アプリケーション UI を通じて実行されず、意味のあるビジネス シナリオに関係するすべてのプログラム ユニットを実行する皮下テストに特に注目します。

Even though subcutaneous tests include the interaction between multiple units, particular tests may not be interested in exercising all components, layers, or sub-systems involved.
皮下テストには複数のユニット間の相互作用が含まれますが、特定のテストでは、関連するすべてのコンポーネント、レイヤー、またはサブシステムを実行することを目的としていない場合があります。
Such parts of the system may then be "mocked away" (or faked), so that the code under test runs in isolation from them.
システムのそのような部分は「モック化」 (または偽造) され、テスト対象のコードはそれらから分離して実行されるようになります。
Therefore, the ability to isolate the code under test from certain parts of the system is generally useful in all kinds of tests.
したがって、テスト対象のコードをシステムの特定の部分から分離する機能は、一般的にあらゆる種類のテストで役立ちます。
That said, in general it's best to make a test as "realistic" as we can.
そうは言っても、一般的には、テストをできるだけ「現実的」なものにするのが最善です。
So, the use of mocking and/or faking should, ideally, be kept to a minimum.
したがって、理想的には、嘲笑や偽装の使用は最小限に抑える必要があります。

2 Testing with mock objects

A common and powerful technique for testing code in isolation is the use of "mocks".
コードを個別にテストするための一般的かつ強力な手法は、「モック」を使用することです。
Traditionally, a mock object is an instance of a class specifically implemented for a single test or set of related tests.
従来、モック オブジェクトは、単一のテストまたは関連するテストのセット用に特別に実装されたクラスのインスタンスです。
This instance is passed to code under test to take the place of one of its dependencies.
このインスタンスはテスト対象のコードに渡され、その依存関係の 1 つに置き換わります。
Each mock object behaves in the way expected by both the code under test and the tests that use it, so that all tests can pass.
各モック オブジェクトは、テスト対象のコードとそれを使用するテストの両方で期待される方法で動作するため、すべてのテストに合格できます。

JMockit goes beyond conventional mock objects by allowing methods and constructors to be mocked directly on "real" (non-mock) classes, eliminating the need to instantiate mock objects in tests and pass them to code under test; instead, objects created by code under test will execute the mock behavior defined by tests, whenever methods or constructors are called on the real classes.
JMockit は、従来のモック オブジェクトを超え、メソッドとコンストラクタを「実際の」(非モック) クラスで直接モック化できるようにすることで、テストでモック オブジェクトをインスタンス化してテスト対象のコードに渡す必要性を排除します。代わりに、テスト対象のコードによって作成されたオブジェクトは、実際のクラスでメソッドまたはコンストラクタが呼び出されるたびに、テストで定義されたモック動作を実行します。
When a class is mocked, the original implementations of existing methods/constructors are temporarily replaced with mock implementations, usually for the duration of a single test.
クラスがモック化されると、既存のメソッド/コンストラクターの元の実装が、通常は単一のテストの期間中、一時的にモック実装に置き換えられます。
This mocking approach applies not only to public instance methods, but also to final and static methods, as well as constructors.
このモック化アプローチは、パブリック インスタンス メソッドだけでなく、最終メソッド、静的メソッド、およびコンストラクターにも適用されます。

3 An example

Consider a business service class which provides a business operation with the following steps:
次の手順でビジネス操作を提供するビジネス サービス クラスを考えてみましょう。

  1. find certain persistent entities needed by the operation
    操作に必要な特定の永続エンティティを見つける
  2. persist the state of a new entity
    新しいエンティティの状態を保持する
  3. send a notification e-mail to an interested party
    関係者に通知メールを送信する

The first two steps require access to the application database, which is done through a simplified API to the persistence subsystem (which itself uses JPA).
最初の 2 つの手順では、アプリケーション データベースへのアクセスが必要です。これは、永続性サブシステム (それ自体が JPA を使用) への簡略化された API を介して実行されます。
The third one can be achieved with a third-party API for sending e-mail, which in this example is Apache's Commons Email library.
3 番目は、電子メールを送信するためのサードパーティ API を使用して実現できます。この例では、Apache の Commons Email ライブラリです。

Therefore, the service class has two separate dependencies, one for persistence and another for e-mail.
したがって、サービス クラスには、永続性に関する依存関係と電子メールに関する依存関係の 2 つの別個の依存関係があります。
To test the business operation, we rely on JMockit's JPA support to deal with persistence, while mocking the e-mail API.
ビジネス操作をテストするために、電子メール API をモックしながら、永続性を処理するために JMockit の JPA サポートに依存します。
Complete source code for a working solution - with all tests - is available online.
実用的なソリューションの完全なソース コード (すべてのテストを含む) はオンラインで入手できます。

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) { ... } }

The Database class contains only static methods and a private constructor; the find and persist methods should be obvious, so we won't list them here.
Database クラスには、静的メソッドとプライベート コンストラクターのみが含まれています。find メソッドと persist メソッドは明らかなので、ここではリストしません。

So, how can we test the "doBusinessOperationXyz" method without making any changes to the existing application code?
では、既存のアプリケーション コードを変更せずに「doBusinessOperationXyz」メソッドをテストするにはどうすればよいでしょうか?
In the following JUnit test class, each test will verify the correct execution of persistence operations, as well as the expected invocations to the e-mail API.
次の JUnit テスト クラスでは、各テストで永続化操作の正しい実行と、電子メール API への予期される呼び出しが検証されます。
These verification points are the ones numbered (1)-(4) as indicated above.
これらの検証ポイントは、上記に示した(1)~(4)の番号が付けられたポイントです。

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(); } }

The example test uses a couple of annotations from the JMockit API.
サンプルテストでは、JMockit API のいくつかのアノテーションを使用します。
@Tested takes care of setting up properly initialized objects to be tested, while @Mocked applies mocking to a given type.
@Tested はテスト対象として適切に初期化されたオブジェクトの設定を処理し、@Mocked は指定された型にモックを適用します。

As also shown in the test, the recording (inside a new Expectations() {{ ... }} block) and the verification (inside a new Verifications() {{ ... }} block) of expectations is achieved simply by invoking the desired methods (as well as constructors, even if not shown here) on mocked types/instances from inside the recording or verification block.
テストでも示されているように、期待値の記録 (new Expectations() {{ ... }} ブロック内) と検証 (new Verifications() {{ ... }} ブロック内) は、記録または検証ブロック内からモック化された型/インスタンスに対して必要なメソッド (およびここに示されていない場合でもコンストラクター) を呼び出すだけで実現されます。
Values to return (or exceptions to throw) from matching invocations executed by the code under test are specified during recording through the "result" field.
テスト対象のコードによって実行される一致する呼び出しから返される値 (またはスローされる例外) は、記録中に「結果」フィールドを通じて指定されます。
Invocation count constraints can be specified, either when recording or when verifying, through API field assignments like "times = 1".
呼び出し回数の制約は、記録時または検証時に、「times = 1」などの API フィールド割り当てを通じて指定できます。

4 Running tests with JMockit

To run tests that use any of the JMockit APIs, use your Java IDE, Maven/Gradle build script, etc. the way you normally would.
JMockit API のいずれかを使用するテストを実行するには、通常どおり Java IDE、Maven/Gradle ビルド スクリプトなどを使用します。
In principle, any JDK of version 1.7 or newer, on Windows, Mac OS X, or Linux, can be used.
原則として、Windows、Mac OS X、Linux 上のバージョン 1.7 以降の JDK を使用できます。
JMockit supports (and requires) the use of JUnit (version 4 or 5) or TestNG; specifically, you need to:
JMockit は JUnit (バージョン 4 または 5) または TestNG の使用をサポート (および必須) します。具体的には、次の操作が必要です。

4.1 Running tests from Maven

The JMockit artifacts are located in the central Maven repository.
JMockit アーティファクトは、中央 Maven リポジトリにあります。
To use them in a test suite, add the following to your pom.xml file:
テスト スイートでこれらを使用するには、pom.xml ファイルに次のコードを追加します。

<dependencies>
   <dependency>
      <groupId>org.jmockit</groupId>
      <artifactId>jmockit</artifactId>
      <version>${jmockit.version}</version>
      <scope>test</scope>
   </dependency>
</dependencies>

Make sure the specified version (here specified in the "jmockit.version" property) is the one you actually want.
指定されたバージョン (ここでは「jmockit.version」プロパティで指定) が実際に必要なバージョンであることを確認します。
Find the current version in the development history page.
開発履歴ページで現在のバージョンを見つけてください。
JMockit also requires the -javaagent JVM initialization parameter to be used; when using the Maven Surefire plugin for test execution, it's specified as follows:
JMockit では、-javaagent JVM 初期化パラメータも使用する必要があります。テスト実行に Maven Surefire プラグインを使用する場合は、次のように指定します。

<plugins>
   <plugin>
      <artifactId>maven-surefire-plugin</artifactId>
      <version>2.22.2</version> <!-- or some other version -->
      <configuration>
         <argLine>
            -javaagent:"${settings.localRepository}"/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar
         </argLine>
      </configuration>
   </plugin>
</plugins>

For information on using JMockit Coverage with Maven, see the relevant section in that chapter.
Maven で JMockit Coverage を使用する方法については、その章の関連セクションを参照してください。

4.2 Running tests from Gradle

Gradle will also download the necessary artifacts from the mavenCentral() repository.
Gradle は mavenCentral() リポジトリから必要な成果物もダウンロードします。
In your gradle.build file, add the jmockit dependency and test configuration, replacing the number of the desired version if needed:
gradle.build ファイルに、jmockit 依存関係とテスト構成を追加し、必要に応じて目的のバージョン番号を置き換えます。

repositories {
    mavenCentral()
}

def jmockitVersion = '1.xy'

dependencies {
   ... "compile" dependencies ...
   testImplementation "org.jmockit:jmockit:$jmockitVersion"
}

test {
    jvmArgs "-javaagent:${classpath.find { it.name.contains("jmockit") }.absolutePath}"
}