1. はじめに
本チュートリアルでは、Java製の「ダイスゲーム」を題材に、JUnit や assert を使わずに System.out.println
出力だけでテストを行う手法を学びます。IDE には Pleiades を使用し、手軽なコンソール確認ベースのテスト手順を身につけることを目指します。
今回の単体テスト、結合テスト、システムテストの範囲は以下のとおりです。

対象読者
- Java の基本文法やクラス設計は理解しているが、テストの経験が浅い方
- JUnit などのフレームワークをまだ導入しておらず、手動・目視でのテストからスタートしたい方
- Pleiades(Eclipse ベース)で開発を行っている新人エンジニア
なぜ JUnit/assert を使わずに学ぶのか
- テストコードの最初の一歩として、まずは「動作確認」の流れを理解する
- 外部ライブラリや依存を増やさずに、「自作コードを素のまま検証する」感覚を養う
- 後にフレームワーク導入した際の差分やメリットがより実感しやすくなる
Pleiades IDE でのテストの流れ
- Java プロジェクトにテスト用クラス(メインメソッド)を追加
- 対象クラス(Dice, DiceGame)を呼び出し、
System.out.println
で結果を出力 - コンソールビューを開いてログを目視確認
- 問題があればソースを修正し、再度実行
テスト対象コード
以下のコードをテスト対象とします。
package diceGame;
import java.util.Random;
/**
* Dice クラスは、6面のサイコロを表現するクラスです。 インスタンス化するとサイコロを1つ生成し、振ることで1〜6の目をランダムに得ることができます。
* 各目は対応する絵文字(⚀〜⚅)で表現されます。
*
* @author Yusei Yamazaki
* @version 1.0.0
*/
public class Dice {
/**
* サイコロの現在の目の値を表します。初期値は1です。
*/
private int faceValue = 1;
/**
* 各サイコロの目に対応する絵文字を格納する配列です。 インデックス0〜5にそれぞれ⚀〜⚅が格納されています。
*/
private char[] faces = { '⚀', '⚁', '⚂', '⚃', '⚄', '⚅' };
/**
* 乱数生成器。サイコロの目をランダムに決めるために使用されます。
*/
private Random r;
/**
* コンストラクタ。乱数生成器のインスタンスを初期化します。
*/
public Dice() {
r = new Random();
}
/**
* サイコロを振って、1〜6のいずれかの目の値をランダムに設定します。
*/
public void roll() {
faceValue = r.nextInt(6) + 1; // 0〜5に1を加えることで1〜6の値にする
}
/**
* 現在のサイコロの目の値(数値)を取得します。
*
* @return 現在のサイコロの目の値(1〜6)
*/
public int getFaceValue() {
return faceValue;
}
/**
* 現在のサイコロの目を対応する絵文字で取得します。
*
* @return faceValue に対応する絵文字(⚀〜⚅)
*/
public char getFace() {
return faces[faceValue - 1]; // faceValueは1始まりなので、インデックスに合わせて-1
}
}
package diceGame;
import java.util.Scanner;
/**
* DiceGame クラスは、2つのサイコロを使ってプレイヤーが無料または有料になるかを判定する簡単なゲームを提供します。 サイコロの合計が 5〜8
* であれば「無料」、それ以外は「有料」となります。 サイコロの目が1だった場合は赤色で表示されます。
*
* @author Yusei Yamazaki
* @version 1.0.0
*/
public class DiceGame {
// ANSI エスケープコード(赤色)の定義。数字「1」の目を強調表示するために使う。
public static final String ANSI_RED = "\u001B[31m";
public static final String ANSI_RESET = "\u001B[0m";
/**
* 1つ目のサイコロオブジェクト。
*/
Dice d1;
/**
* 2つ目のサイコロオブジェクト。
*/
Dice d2;
/**
* DiceGame のコンストラクタ。 ゲーム開始時に2つのサイコロを生成する。
*/
public DiceGame() {
this.d1 = new Dice();
this.d2 = new Dice();
}
/**
* ゲームのメイン処理。ユーザーにダイスを振らせ、合計値により無料か有料かを判定する。 ユーザーが Enter キーを押すことでゲームが繰り返される。
*/
public void play() {
while (true) {
System.out.println("2つのサイコロの合計が7~11なら無料になるよ。Enterを押してサイコロを振ってください。");
// ユーザーの入力待ち(Enter を押すと次に進む)
Scanner sc = new Scanner(System.in);
sc.nextLine();
// 1つ目のサイコロを振る
d1.roll();
int num1 = d1.getFaceValue();
// 2つ目のサイコロを振る
d2.roll();
int num2 = d2.getFaceValue();
// サイコロ1の目が1だった場合は赤色で表示
if (num1 == 1) {
System.out.print(ANSI_RED + d1.getFace() + ANSI_RESET);
} else {
System.out.print(d1.getFace());
}
// サイコロ2の目が1だった場合は赤色で表示
if (num2 == 1) {
System.out.println(ANSI_RED + d2.getFace() + ANSI_RESET);
} else {
System.out.println(d2.getFace());
}
// サイコロの合計値を出力
int point = num1 + num2;
System.out.println("point:" + point);
// 合計値に応じたメッセージを出力
System.out.println(judge(point));
}
}
/**
* サイコロの合計値によって「無料」か「有料」かを判定する。
*
* @param point 2つのサイコロの合計値
* @return 判定結果のメッセージ
*/
String judge(int point) {
if (point >= 7 && point <= 11) {
return "やったー、無料です。";
} else {
return "ざんねん、有料です。次はきっと無料だよ。";
}
}
}
package diceGame;
/**
* Main クラスは、ダイスゲームを起動するエントリポイントです。 実行すると DiceGame インスタンスを生成し、ゲームを開始します。
*
* @author Yusei Yamazaki
* @version 1.0.0
*/
public class Main {
/**
* アプリケーションのメインメソッドです。 DiceGame のインスタンスを生成し、ゲームループを開始します。
*
* @param args コマンドライン引数(未使用)
*/
public static void main(String[] args) {
// ゲームを起動
new DiceGame().play();
}
}
2. プロジェクトのセットアップ
Pleiades IDE での新規 Java プロジェクト作成
- Pleiades(Eclipse)を起動し、メニューから
ファイル > 新規 > Java プロジェクト
を選択 - プロジェクト名を入力(例:
DiceGameTestTutorial
)し、完了
をクリック - プロジェクト内にデフォルトで作成される
src
フォルダを使用
パッケージ構成例
diceGame
パッケージに本体クラスを、test
パッケージに各テストクラスを配置- テストクラスはすべて
public static void main(String[] args)
をもつ普通の Java アプリとして実装
テスト実行の準備
- 特別なライブラリやユーティリティは不要。
System.out.println
出力をそのままコンソールで目視確認 - 各テストクラスを右クリック →
実行 > Java アプリケーション
で簡単に起動
3. 単体テスト(Unit Test)
テスト対象クラス:Dice
Dice
クラスは内部で Random
を使っているため、完全な自動検証は難しいですが、 手動で複数回ロールを行い、出力が 1〜6 の範囲かつ絵文字が対応しているかを目視確認します。
テストコード例:TestDice.java
package diceGame;
/**
* Dice クラスの単体テスト。 roll() を複数回実行し、出力を目視で確認する。
*/
public class TestDice {
public static void main(String[] args) {
Dice dice = new Dice();
// サンプルとして10回振ってみる
for (int i = 1; i <= 10; i++) {
dice.roll();
int value = dice.getFaceValue();
char face = dice.getFace();
System.out.println("roll " + i + " → value=" + value + ", face=" + face);
}
}
}
確認ポイント
- 出力される
value
が必ず 1〜6 の整数であること face
が⚀
〜⚅
のいずれかであること- 同じインスタンスで連続実行しても、値が偏りすぎていないこと(ランダム性の目視確認)
テスト対象メソッド:DiceGame.judge(int point)
DiceGame
クラスの判定ロジック(合計値が 7~11 なら「無料」、それ以外は「有料」)を、 Dice
を使わず固定のポイント値で呼び出し、期待どおりのメッセージが返るかを確認します。(限界値分析)
テストコード例:TestJudge.java
package diceGame;
/**
* DiceGame の judge() メソッドを単体テストするクラス。 固定ポイントを渡して、出力メッセージを目視で確認する。
*/
public class TestJudge {
public static void main(String[] args) {
DiceGame game = new DiceGame();
int[] testPoints = { 2, 6, 7, 11, 12 };
for (int p : testPoints) {
String result = game.judge(p);
System.out.println("point=" + p + " → " + result);
}
}
}
確認ポイント
point=2
およびpoint=6
およびpoint=12
のときは「ざんねん、有料です。次はきっと無料だよ。」が出力されるpoint=7
およびpoint=11
のときは「やったー、無料です。」が出力される- メッセージ文言の誤字脱字がないこと
4. 結合テスト(Integration Test)
Dice
クラスと DiceGame
クラスの連携動作を確認するために手動検証形式で、出力を目視確認した。
テスト対象
- クラス
diceGame.Dice
diceGame.DiceGame
- メソッド
Dice.roll()
Dice.getFaceValue()
DiceGame.judge(int point)
テストコード例:TestDice.java
package diceGame;
/**
* Dice と DiceGame を連携させた結合テスト。 実際にダイスを振り、ゲームロジックを通して結果を確認する。
*/
public class TestDiceGameIntegration {
public static void main(String[] args) {
DiceGame game = new DiceGame();
// テストを10回繰り返して Dice → judge の連携を確認する
for (int i = 0; i < 10; i++) {
// ダイスを振る
game.d1.roll();
game.d2.roll();
// 出た目の値を取得
int num1 = game.d1.getFaceValue();
int num2 = game.d2.getFaceValue();
// 合計を算出
int point = num1 + num2;
// 判定
String result = game.judge(point);
// 出力結果を表示(目 + 合計 + 判定)
System.out.println("Roll " + (i + 1));
System.out.println("Dice1: " + num1 + " (" + game.d1.getFace() + ")");
System.out.println("Dice2: " + num2 + " (" + game.d2.getFace() + ")");
System.out.println("Total: " + point);
System.out.println("Result: " + result);
System.out.println("--------------------------");
}
}
}
5. システムテスト(System Test)
目的
本テストでは、チンチロリンハイボールゲームで「無料」と判定される確率が 55%±1% になるかを 統計的に検証します。
試行回数とフロー
- 試行回数:100,000 回
- テストフロー:
- 内部の 2 つのサイコロ(
game.d1
,game.d2
)を100,000回振る - 出目の合計が 7~11 の場合を「無料」としてカウント
- 無料回数/全試行数から無料率を算出
- 内部の 2 つのサイコロ(
テストコード例:TestDiceGameStat.java
package diceGame;
/**
* DiceGame のシステムテスト。 100,000 回試行し、無料率が 55%±1% の範囲内かを検証する。
*/
public class TestDiceGameSystem {
public static void main(String[] args) {
DiceGame game = new DiceGame();
int trials = 100_000;
int freeCount = 0;
for (int i = 0; i < trials; i++) {
game.d1.roll();
game.d2.roll();
int sum = game.d1.getFaceValue() + game.d2.getFaceValue();
if (sum >= 7 && sum <= 11) {
freeCount++;
}
}
double rate = freeCount * 100.0 / trials;
System.out.println("試行回数: " + trials);
System.out.println("無料回数: " + freeCount);
System.out.println("無料率: " + rate + "%");
if (rate >= 54 && rate <= 56) {
System.out.println("※無料率は 55%±1% の範囲内です。");
} else {
System.out.println("※無料率は 55%±1% の範囲外です。");
}
}
}
確認ポイント
- 出力される無料率が 54〜56% の範囲内に収まっているか
- コンソールに試行回数・無料回数・無料率・判定メッセージが正しく表示されるか
- 100,000 回の試行にかかる時間が数秒程度で収まっているか