JUnitを使用したメソッドの実行とモックのかけ方

ご注意！
---
個人の勉強目的としてここに残しています！
参考になるかは分かりません。

対象
---
:thinking:　未来でJUnitに困った自分
:beginner:　JUnitが初めての人
:alarm_clock:　JUnitがとっても久しぶりの人
:disappointed_relieved:　モックのかけ方何だっけ？って人

この記事を読んで期待できること
---
（１）メソッドの呼び出し方(サンプルソース付)
（２）モックのかけ方(サンプルソース付)
（３）テストクラスとテスト対象クラスのザックリとした関係性(イメージ画付)

長いけど順を追っていくと、（１）と（２）は使いこなせるようになるかと！

目次
---
・環境
・（１）メソッドの呼び出し方(サンプルソース付)
・（２）モックのかけ方(サンプルソース付)
・（３）テストクラスとテスト対象クラスの関係性(イメージ画付)
・テスト対象クラスとテストクラスの全体を解説付きで見てみよう
・最後に


環境
---
・JUnit4
・Jmockit
・eclipse
・Java SE5(SE7,8でも検証済)

テストクラスの自動生成
---
[こちら](http://www.okapiproject.com/java/java_tools/eclipse/vol_2/eclipse_junitfuncion.htm
)を参考にした



（１）メソッドの呼び出し方(サンプルソース付)
---
▼メソッドを呼び出すコード

```java
Method method = 【クラス名】.class.getDeclaredMethod("【メソッド名】", 【引数の型】.class);
method.setAccessible(true);
method.invoke(【インスタンス名】, 【引数】);
```
◆解説
1行目：クラスと実行するメソッド名、引数(あれば)を記載。
引数は「**String.class**」とか「**int.class**」というように引数の型を書く。書くのは**引数の型**だよ！

2行目：メソッドにアクセスできるかの判定。
ここがtrueならprotectedもprivateも外部から呼びだしてテストできる。

3行目：invokeが実行するメソッド。ここにインスタンス生成したのと引数を渡してあげる。
これで基本実行できるが、できない場合**呼び出すのに情報が足りてない**か、**呼び出し先で落ちている**ことが大半。

例）

```java

// テスト対象クラスのインスタンス生成・・（A）
Test sample = new Test();

// 引数の設定・・（B）
String moji = "ネコ型ロボット";
int suuji = 2112903;

// メソッド実行・・（C）
Method method = Test.class.getDeclaredMethod("testMethod", String.class, int.class);
method.setAccessible(true);
method.invoke(sample, moji, suuji);
```
◆解説
（A）：テスト対象クラスのインスタンス生成。このインスタンス名は（C）の一番下で使用する。

（B）：メソッドを実行する際の引数をここで定義する！（C）の一番下で使用する。

（C）：今回は2つ引数があるので1行目で「String.class」「int.class」の2つ記載している。ここは**引数の数だけ追記**する！
当然、**引数なしのメソッドの場合は記載しない**！
順番はテストしたいメソッドの引数の順番通りに記載すること。


（２）モックのかけ方(サンプルソース付)
---
▼モックをかけるコード

```java
new MockUp<【クラス名】>(){
	@Mock
	【ここにモックをかけたいメソッドをべた書き】{
		return 【ここに記載したものが返却される】;
		　　　　　※voidの場合はreturnはないけど。
	}
};
```
◆解説
解説するよりこのままコピペして【】の中をカスタマイズして使ってほしい。あとは例を見てみよう！

例）

```java
new MockUp<sample>(){
	@Mock
	public String testMethod(String moji, int suuji) {
		String result = "こんにちは、ぼくドラえもんです";
		return result ;
	}
};
```
◆解説
1行目：<>の中にテストクラスを記載
2行目：@Mockは準備されているもの！なので気にしない
3行目：**ここはテストしたいメソッドをべた書きしてください！**後で解説します！
4、5行目：モックで何を返却したいかをテストする人が決められるところです。ここで言うなら、testMethodメソッドから返却されるであろう値を「return」で返してあげよう！とのこと。


（３）テストクラスとテスト対象クラスの関係性(イメージ画像 付)
---
え、なんでテストクラスに引数を全部用意しないといけないの？！
メソッド呼出ているんだから値取得出来ているでしょ！

とか思っていてとても苦労したので図にしてざーーくりと理解した。
（個人メモ目的なので分かりづらかったらごめんね！！）

▼最初思っていた関係性
![JUnit理解001.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491501/25490d9d-5920-7d04-d4a9-4f67a6805b72.png)

てっきりテストクラスからテスト対象クラスを呼び出していると思ってた。

▼実際こんな関係性
![JUnit理解002.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491501/159d5656-b8e5-ccf3-15ea-8b0001177b09.png)

後ろにくっついているようなイメージらしい。
**後ろにくっついている＝値を渡してあげないといけない**というのがすんなり入ってきた。




テスト対象クラスとテストクラスの全体を解説付きで見てみよう
---
あの素晴らしい、国民的アニメドラえもんの風景でJUnitを学んでいこう。
(自分の好きなものでこういうのやると案外はかどる。)

【テスト対象クラス】
・Nobita.java
・Doraemon.java

【テストクラス】
・NobitaTest.java
・DoraemonTest.java

```java:Nobita.java

package nobita;

import doraemon.Doraemon;

public class Nobita {

	public void NobitaHelp() {

		Doraemon dora = new Doraemon();

		int point = 0;
		System.out.println("のび太「0点取っちゃった！何とかしてよドラえもん～」");

		String GetTool = dora.help(point);

		if (GetTool != null) {
			System.out.println("のび太「ん！何だかやる気が出てきたぞ！」");
		} else {
			System.out.println("のび太「スヤア。。。」");
			System.out.println("ドラえもん「起きろー！」");
		}
	}
}


```


```java:Doraemon.java

package doraemon;

public class doraemon {

	public String help(int point) {

		String tool = null;

		if (point == 0) {
			System.out.println("ドラえもん「まったく、君というやつは・・」");
			tool = secretTool();
		} else {
			System.out.println("ドラえもん「頑張ったじゃないか！見直したよのび太君」");
			return null;
		}
			return tool;
	}

	public String secretTool() {

		String secretTool = "変身うちわ";
		System.out.println("ドラえもん「" + secretTool + "!」");
		return secretTool;
	}
}

```


#### ▼まずは、Nobita.javaのテストコード！

```java:NobitaTest.java
package nobita;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

import doraemon.doraemon;
import mockit.Mock;
import mockit.MockUp;

public class NobitaTest {

	/*****************************************
     * NobitaHelpメソッドのテスト 
     * throws は自動でinportするので今は気にしない！
     ******************************************/

	@Test
	public void test001_NobitaHelp() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

		Nobita nobi = new Nobita();

		new MockUp<doraemon>(){
			@Mock
			public String help(int point) {
// Nobita.javaのif文でifの中に入るテストを実施するときは上の処理をコメントアウトする。
				String doraemonAction = "変身うちわ";
// Nobita.javaのif文でelseのテストを実施するときは下の処理をコメントアウトする。
				//String doraemonAction = null;
				return doraemonAction;
			}
		};

		Method method = Nobita.class.getDeclaredMethod("NobitaHelp");
		method.setAccessible(true);
		method.invoke(nobi);
		System.out.println("----- テスト終了 -----");
	}
}

```

JUnitを実行すると、、

**のび太「0点取っちゃった！何とかしてよドラえもん?」**
**のび太「ん！何だかやる気が出てきたぞ！」**
**----- テスト終了 -----**

このように返ってきたら成功だ！



#### ▼お次にDoraemon.javaのテストコード
```java:DoraemonTest.java

package doraemon;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

@FixMethodOrder (MethodSorters.NAME_ASCENDING)
// ↑この1文はこのテストクラスに記載されているメソッドの名前順、数字の若い順にテストをしてくれるもの。これを記載しないとバラバラにテストが実行されます。

public class DoraemonTest {

	/*****************************************
     * Helpメソッドのテスト 
     * throws は自動でinportするので今は気にしない！
     ******************************************/
	@Test
	public void test001_Help() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

		Doraemon dora = new Doraemon();

		int point = 0;

		Method method = Doraemon.class.getDeclaredMethod("help", int.class);
		method.setAccessible(true);
		method.invoke(dora, point);
		System.out.println("----- テスト終了 -----");
	}

	/*****************************************
     * SecretToolメソッドのテスト 
     * throws は自動でinportするので今は気にしない！
     ******************************************/
	@Test
	public void test002_SecretTool() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Doraemon dora = new Doraemon();

		Method method = Doraemon.class.getDeclaredMethod("secretTool");
		method.setAccessible(true);
		method.invoke(dora);
		System.out.println("----- テスト終了 -----");
	}
}

```

JUnitを実行すると、、

**ドラえもん「まったく、君というやつは・・」**
**ドラえもん「変身うちわ!」**
**----- テスト終了 -----**
**ドラえもん「変身うちわ!」**
**----- テスト終了 -----**

という感じに成功だ！


最後に
---
JUnitはメソッドの実行とモックのかけ方を覚えると急速にはかどる。（経験談）

この記事は、未来でJUnitをやることになり困っている自分に贈る。笑