自分が作ったクラスのインスタンスメソッドをスタブに置き換える

# 概要

自分が作ったクラスのインスタンスを使っているメソッドを, テスト可能にする.

# 問題のコード

```csharp
class Motor
{
	/// <summary>
	/// 現在の速度を取得または設定する
	/// </summary>
	public int Speed
	{
		get
		{
			// このコードは, 実機にモーターが
			// 繋がっていないと動作しない.
			// (テスト環境では動作させることはできない)
		}
		set
		{
			// このコードも上と同様, テスト環境では動かせない
		}
	}
}

class SampleClass
{
	/// <summary>
	/// テスト対象のメソッド
	/// </summary>
	/// <param name="motor">処理したいモーター</param>
	public void SampleMethod(Motor motor)
	{
		int currentSpeed = motor.Speed;
		
		// currentSpeedを取得して何か処理する.
		// 省略する.
	}
```

このコードは, 特別なデバイス(実機)上で動作させるものとする.
実機にはモーターが接続されており, `Motor`クラスを通じて制御をおこなう.
`Motor`クラスは自分で定義したものであり, `SampleMethod`メソッドはそのインスタンスを使って, 何か処理する.

この`SampleMethod`メソッドのテストを作成し, CIツール(Travis CIとかAppVeyorとか)で自動テストさせたい.
でも, CIツールの環境では, モーターが接続されていないので, `Speed`プロパティは動作しない.
テストの時は, `Motor.Speed`は呼ばず, 代わりのメソッドを呼ぶようにしたい.

以降で, `Motor`インスタンスをスタブに置き換えて, `SampleMethod`メソッドをテストできるようにしてみる.

# クラスではなくインタフェースに依存させる

問題のメソッドでは, モーターを`Motor`インスタンスとして受け取り, `Motor.Speed`プロパティを呼んでいる.
`Motor`インスタンスとして受け取っているので, `Motor`クラスのプロパティが呼ばれるのは当たり前である.
これを, スタブのメソッドが呼ばれるようにするためには,
__クラスではなくインタフェースに依存させる__
ということをする.

具体的には, `Motor`クラスを, `IMotor`インタフェースの実装クラスとする.

```csharp
interface IMotor
{
	int Speed { get; set; }
}

class Motor : IMotor
{
	/// <summary>
	/// 現在の速度を取得または設定する
	/// </summary>
	public int Speed
	{
		get
		{
			// このコードは, 実機にモーターが
			// 繋がっていないと動作しない.
			// (テスト環境では動作させることはできない)
		}
		set
		{
			// このコードも上と同様, テスト環境では動かせない
		}
	}
}
```

そして, テスト対象のメソッドは次のようにする.

```csharp
/// <summary>
/// テスト対象のメソッド
/// </summary>
/// <param name="motor">処理したいモーター</param>
public void SampleMethod(IMotor motor)	// Motorではなく, IMotorとして受け取る
{
	int currentSpeed = motor.Speed;

	// currentSpeedを取得して何か処理する.
	// 省略する.
}
```

どこが変わったか分かりにくいかもしれないが, モーターを`Motor`インスタンスではなく, `IMotor`インタフェース(を持つインスタンス)として受け取っている.
そして, `IMotor`インタフェースの`Speed`プロパティを呼んでいる.

こうすることで, `IMotor`インタフェースを実装しているものなら何でも受け取ることができる.
実機で動かすときは`Motor`インスタンスを受け取り, テストの時にはスタブインスタンスを受け取る, ということができるのである.
そして`SampleMethod`メソッド内では, 実際の実装がどのようになっているかを気にすることなく, `IMotor.Speed`プロパティを呼び出せば, それぞれの実装に合わせた処理が実行される.

# スタブに入れ替えてみる

まずはスタブを用意する.
もちろん`IMotor`インタフェースを実装させる.

```csharp
class MotorStub : IMotor
{
	public int Speed
	{
		get
		{
			// ただ定数値を返す
			return 0;
		}
		set
		{
			// 何もしない
		}
	}
}
```

テストコードは次のようになる.

```csharp
[TestMethod]
public void SampleMethodTest()
{
	// Arrange (準備)
	SampleClass instance = new SampleClass();
	IMotor inputMotor = new MotorStub();

	// Act (実行)
	instance.SampleMethod(inputMotor);

	// Assert (検証)
	// 何か処理が行われたことを確認する
	// 今回は省略
}
```

これで, `SampleMethod`メソッド内では, なにもせずただ0を返すだけの`MotorStub.Speed`プロパティが呼ばれるだろう.
本記事の目的は達成された.

![class.png](https://qiita-image-store.s3.amazonaws.com/0/109703/7300c6ac-e10e-a15d-d744-8ffcef12da7f.png)

# スタブをもう少し便利に

ここまでで, 当初の目的は達成することができた.
ここからは, スタブクラスをちょっと便利に改造する.

前節で作ったスタブのクラスは, いつも定数値0を返す.
しかし, テストによっては0を返してほしいテストとか, 1を返してほしいテストとか, いろいろある.
そのたびに新たなスタブクラスを作るのはめんどくさいので, 返す値を指定することができるようにしてみる.

```csharp
class MotorStub : IMotor
{
	public int SpeedValue;

	public int Speed
	{
		get
		{
			// ただSpeedValueを返す
			return SpeedValue;
		}
		set
		{
			// 何もしない
		}
	}
}
```

テストをするときは, 返す値を設定することになる.

```csharp
[TestMethod]
public void SampleMethodTest()
{
	// Arrange (準備)
	SampleClass instance = new SampleClass();
	IMotor inputMotor = new MotorStub();
	((MotorStub)inputMotor).SpeedValue = 1;	// Speedプロパティが返す値を設定

	// Act (実行)
	instance.SampleMethod(inputMotor);

	// Assert (検証)
	// 何か処理が行われたことを確認する
	// 今回は省略
}
```

さらにテストによっては, `Speed`プロパティに特定の例外を発生させたいとか, 1回目に呼ばれたときは0で2回目に呼ばれたときは1を返すようにしたいとか, 複雑なことをさせたいこともある.
本記事では説明しないが, またどこかで説明するかもしれない.
ちなみに, "どんな呼ばれ方をするか"とか, "こういう値を返したときの処理"とかを確認したい場合は, "スタブ"ではなく"モック"になる.