0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JUnitの学習②_スタブについて

Last updated at Posted at 2025-04-16

この記事はプログラミング初心者が自分のメモ用として書いている記事です。
そのため、誤った情報が記述されている可能性があります。
自己判断で読み進めてください

スタブ(Stub)とは?

スタブとは、ユニットテストにおいて「他のクラスから呼ばれると、決まった値を返す」だけの簡易的な代用品のこと。

別のクラスやコンポーネントに依存しているロジックを、テスト用に簡易化して置き換える際に使う、

たとえば、毎回値が変わる Random のような処理を「固定の値で返す」ことで、テストを安定させる目的で使用されるケースで説明する。


サンプルソース解説とその役割

以下は、実際のスタブの構成。

インターフェース RandomNumber

package junit.sample;

public interface RandomNumber {
	int nextInt();
}

✅【目的】

  • ランダム値を生成するインターフェース。
  • 実装を差し替えるための“共通の型”として使う。

本来の実装 RandomNumberImpl

package junit.sample;

import java.util.Random;

public class RandomNumberImpl implements RandomNumber {
	private final Random random = new Random();
	@Override
	public int nextInt() {
		return random.nextInt();
	}
}

✅【目的】

  • 実際のランダム値を返す処理です。
  • テストでは「毎回違う結果」になり不安定になる原因です。

✅【このコードの代わりにスタブを使う理由】

  • テスト時に nextInt() の戻り値が毎回異なると、「期待値がブレる=テスト失敗」になります。

スタブ RandomNumberStub

package junit.sample;

public class RandomNumberStub implements RandomNumber {
	@Override
	public int nextInt() {
		return 0;
	}
}

✅【目的】

  • 毎回「0」を返す簡易実装。
  • RandomNumberImpl を「決まった結果にする」ためのスタブ。
  • これにより、常に「index 0」の値(例:「A」)が選ばれるようになります。

対象クラス Randoms

package junit.sample;

import java.util.List;

public class Randoms {
	RandomNumber random = new RandomNumberImpl();

	public <T> T choice(List<T> options) {
		if (options.size() == 0) {
			return null;
		}
		int index = random.nextInt() % options.size();
		return options.get(index);
	}
}

✅【ポイント解説】

  • choice() メソッドは、与えられたリストからランダムに1件選びます。
  • randomRandomNumber 型なので、実際には RandomNumberImplRandomNumberStub を注入できます。
  • ユニットテスト時に外から random を差し替えることができる設計になっている点が重要です。

テストクラス RandomsTest

package junit.sample;

import static org.junit.jupiter.api.Assertions.*;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import org.junit.jupiter.api.Test;

public class RandomsTest {

	@Test
	void testChoice() {
		List<String> options = new ArrayList<>();
		options.add("A");
		options.add("B");
		Randoms sut = new Randoms();

		// ラムダ表現のスタブを直接設定
		final AtomicBoolean isCalled = new AtomicBoolean(false);
		sut.random = new RandomNumber() {
			@Override
			public int nextInt() {
				isCalled.set(true); // 呼び出し確認
				return 0; // "A"を選ばせる
			}
		};
		// または sut.random = new RandomNumberStub(); でも可

		assertEquals(sut.choice(options), "A");
		assertTrue(isCalled.get());
	}
}

✅【ポイント解説】

  • sut.random にスタブ(匿名クラス or RandomNumberStub)を代入
  • テストの意図:「Aが選ばれる状況を強制的に作る」
  • AtomicBoolean により「本当に呼ばれたか」も検証

なぜスタブを使うのか?(現場での観点)

❌ スタブを使わない場合

Randoms sut = new Randoms();
sut.random = new RandomNumberImpl();
  • nextInt() の返り値が毎回ランダムなため、テスト結果が不安定になります
  • 例:期待は「A」だったが、nextInt() が 1 を返して「B」になり失敗するなど

これは "テストが壊れやすい" 状況となり危険。


✅ スタブを使うと?

  • 「常に0を返す」スタブを使えば、100%同じ状態で再現できる
  • 意図的に「index 0の選択肢(A)」が選ばれるため、期待値との一致が保証される
  • これにより、テストの信頼性を向上させられる。

まとめ

スタブは「決まった値を返す」だけのテスト用の代用クラス |
本物の部分の代わりにスタブを使うと、テストを定義的にできる |
例えば、毎回値が変わるRandomをスタブで置き換えることで、結果を統一できる |

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?