PowerMock+Mockito1xでのケース別モックのかけかた

# 概要
Mockito1xでのケース別モックのかけかた
https://qiita.com/taka_22/items/0c13aacf6ffbc2c77970
の続き。

# 前提
Mockito 1.10.19
PowerMock 1.7.3
JUnit 4.11
Java 1.8.0_151

# ケース
依存オブジェクトをnewで生成しているケース、staticメソッド、privateメソッドを扱います。前回のパターンも踏まえて、以下の12パターンに分類しました。

| No | パターン | モック対象メソッドの戻り型 | モック範囲 | モック動作 |
|:-:|:------:|:-------------------------:|:------------------:|:-------------------------------------:|
|7| モックしたいクラスがnewで生成されている | void以外 | 全体 | 指定した戻り値を返す |
|8| モックしたいクラスがnewで生成されている | void以外 | 全体 | 例外を投げる |
|9| モックしたいクラスがnewで生成されている | void | 全体 | 例外を投げる |
|10| モック対象がstaticメソッド | void以外 | 全体 | 指定した戻り値を返す |
|11| モック対象がstaticメソッド | void以外 | 全体 | 例外を投げる |
|12| モック対象がstaticメソッド | void | 全体 | 例外を投げる |
|13| モック対象がprivateメソッド | void以外 | 全体 | 指定した戻り値を返す |
|14| モック対象がprivateメソッド | void以外 | 全体 | 例外を投げる |
|15| モック対象がprivateメソッド | void | 全体 | 例外を投げる |
|16| モック対象がprivateメソッド | void以外 | 一部のメソッドのみ | 指定した戻り値を返す |
|17| モック対象がprivateメソッド | void以外 | 一部のメソッドのみ | 例外を投げる |
|18| モック対象がprivateメソッド | void | 一部のメソッドのみ | 例外を投げる |

# テスト用に作ったクラス
## DateUtil.java
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtil {
	private Boolean flag;
	public static String getCurrentDate() {
		Date d = new Date();
		return new SimpleDateFormat("yyyy/MM/dd").format(d);
	}
	public static void setCurrentDate(long currentTime) {
		Date d = new Date();
		d.setTime(currentTime);
	}
	public String getYYYYMMDDStringWrapper(Date date) throws Exception {
		return getYYYYMMDDString(date);
	}
	private String getYYYYMMDDString(Date date) throws Exception {
		return new SimpleDateFormat("yyyyMMdd").format(date);
	}
	private void setFlag(Boolean flag) throws Exception {
		this.flag = flag;
	}
}


# テストの書き方
## PowerMockでのテストの書き方
1. mock/spy/doThrowといった、Mockitoで使っていたメソッドは、PowerMock専用のものを使う必要があります。
2. @RunWithでPowerMockRunnerを指定する
3. @PrepareForTestでモック対象テストを指定する

import static org.powermock.api.mockito.PowerMockito.doThrow;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.whenNew;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ DateUtil.class })
public class PowerMockTest {
...

## No.7
whenNewでnewで生成されたオブジェクトをモックしたものを返すようにする。

	/**
	 * newで生成されるオブジェクト、publicメソッド、戻り型はvoid以外、全部モック、値を戻す
	 */
	@Test
	public void test007() throws Exception {
		// 期待値は2015/05/05
		Calendar c = Calendar.getInstance();
		c.set(2015, 4, 5);
		Date expected = c.getTime();

		// 記録フェーズ
		Date dateMocked = mock(Date.class);
		whenNew(Date.class).withNoArguments().thenReturn(dateMocked);
		when(dateMocked.getTime()).thenReturn(expected.getTime());

		// リプレイフェーズ
		String strDate = DateUtil.getCurrentDate();

		// 検証フェーズ
		assertThat(strDate, is("2015/05/05"));
	}

## No.8
	/**
	 * newで生成されるオブジェクト、publicメソッド、戻り型はvoid以外、全部モック、例外を投げる
	 */
	@Test
	public void test008() throws Exception {
		// 記録フェーズ
		Date dateMocked = mock(Date.class);
		whenNew(Date.class).withNoArguments().thenReturn(dateMocked);
		when(dateMocked.getTime()).thenThrow(new RuntimeException("aaa"));

		// リプレイ＆検証フェーズ
		try {
			DateUtil.getCurrentDate();
			fail();
		} catch (RuntimeException e) {
			assertThat(e.getMessage(), is("aaa"));
		}
	}

## No.9
	/**
	 * newで生成されるオブジェクト、publicメソッド、戻り型はvoid、全部モック、例外を投げる
	 */
	@Test
	public void test009() throws Exception {
		// 記録フェーズ
		Date dateMocked = mock(Date.class);
		whenNew(Date.class).withNoArguments().thenReturn(dateMocked);
		doThrow(new RuntimeException("bbb")).when(dateMocked).setTime(anyLong());

		// リプレイ＆検証フェーズ
		try {
			DateUtil.setCurrentDate(123456789L);
			fail();
		} catch (RuntimeException e) {
			assertThat(e.getMessage(), is("bbb"));
		}
	}

## No.10
mockStaticでstaticメソッドをモックする。

	/**
	 * public staticメソッド、戻り型はvoid以外、全部モック、値を戻す
	 */
	@Test
	public void test010() {
		// 記録フェーズ
		PowerMockito.mockStatic(String.class);
		PowerMockito.when(String.valueOf(anyBoolean())).thenReturn("false");

		// リプレイ＆検証フェーズ
		assertThat(String.valueOf(true), is("false"));
		assertThat(String.valueOf(false), is("false"));
	}

## No.11
	/**
	 * public staticメソッド、戻り型はvoid以外、全部モック、例外を投げる
	 */
	@Test
	public void test011() {
		// 記録フェーズ
		PowerMockito.mockStatic(String.class);
		PowerMockito.when(String.valueOf(true)).thenThrow(new RuntimeException("aaa"));

		// リプレイ＆検証フェーズ
		try {
			String.valueOf(true);
			fail();
		} catch (RuntimeException e) {
			assertThat(e.getMessage(), is("aaa"));
		}
		assertNull(String.valueOf(false));
	}

## No.12
	/**
	 * public staticメソッド、戻り型はvoid、全部モック、例外を投げる
	 */
	@Test
	public void test012() {
		// 記録フェーズ
		PowerMockito.mockStatic(DateUtil.class);
		try {
			doThrow(new RuntimeException("bbb")).when(DateUtil.class, "setCurrentDate", anyLong());
		} catch (Exception e) {
			fail();
		}

		// リプレイ＆検証フェーズ
		try {
			DateUtil.setCurrentDate(12345L);
			fail();
		} catch (RuntimeException e) {
			assertThat(e.getMessage(), is("bbb"));
		}
	}

## No.13
全体をモックしてしまうので、モックしたメソッドは直接リフレクションで呼び出す。

	/**
	 * privateメソッド、戻り型はvoid以外、全部モック、値を戻す
	 */
	@Test
	public void test013() throws Exception {
		// 記録フェーズ
		DateUtil dateMocked = mock(DateUtil.class);
		PowerMockito.when(dateMocked, "getYYYYMMDDString", (Date) any()).thenReturn("12345678");

		// リプレイフェーズ
		Method getYYYYMMDDStringMethod = DateUtil.class.getDeclaredMethod("getYYYYMMDDString", Date.class);
		getYYYYMMDDStringMethod.setAccessible(true);
		String actual = (String)getYYYYMMDDStringMethod.invoke(dateMocked, new Date());

		// 検証フェーズ
		assertThat(actual, is("12345678"));
	}

## No.14
	/**
	 * privateメソッド、戻り型はvoid以外、全部モック、例外を投げる
	 */
	@Test
	public void test014() throws Exception {
		// 記録フェーズ
		DateUtil dateMocked = mock(DateUtil.class);
		PowerMockito.when(dateMocked, "getYYYYMMDDString", (Date) any()).thenThrow(new Exception("aaa"));

		// リプレイ＆検証フェーズ
		try {
			Method getYYYYMMDDStringMethod = DateUtil.class.getDeclaredMethod("getYYYYMMDDString", Date.class);
			getYYYYMMDDStringMethod.setAccessible(true);
			getYYYYMMDDStringMethod.invoke(dateMocked, new Date());
			fail();
		} catch (Exception e) {
			if (e instanceof InvocationTargetException) {
				InvocationTargetException ite = (InvocationTargetException) e;
				assertThat(ite.getTargetException().getMessage(), is("aaa"));
			} else {
				fail();
			}
		}
	}

## No.15
	/**
	 * privateメソッド、戻り型はvoid、全部モック、例外を投げる
	 */
	@Test
	public void test015() throws Exception {
		// 記録フェーズ
		DateUtil dateMocked = mock(DateUtil.class);
		PowerMockito.doThrow(new Exception("bbb")).when(dateMocked, "setFlag", anyBoolean());

		// リプレイ＆検証フェーズ
		Method setFlagMethod = DateUtil.class.getDeclaredMethod("setFlag", Boolean.class);
		setFlagMethod.setAccessible(true);
		try {
			setFlagMethod.invoke(dateMocked, true);
			fail();
		} catch (Exception e) {
			if (e instanceof InvocationTargetException) {
				InvocationTargetException ite = (InvocationTargetException) e;
				assertThat(ite.getTargetException().getMessage(), is("bbb"));
			} else {
				fail();
			}
		}
	}

## No.16
モックのかけ方は、spyを使うのが違うだけ。あとはNo.13-15と同じ。
全部をモックしないので、publicメソッド経由でテストすることが可能。もちろん、リフレクションでも可能。
	/**
	 * privateメソッド、戻り型はvoid以外、一部モック、値を戻す
	 */
	@Test
	public void test016() throws Exception {
		// 記録フェーズ
		DateUtil dateMocked = spy(new DateUtil());
		PowerMockito.doReturn("12345678").when(dateMocked, "getYYYYMMDDString", (Date) any());

		// リプレイフェーズ
		String strDate = dateMocked.getYYYYMMDDStringWrapper(new Date());

		// 検証フェーズ
		assertThat(strDate, is("12345678"));
	}

## No.17
	/**
	 * privateメソッド、戻り型はvoid以外、一部モック、例外を投げる
	 */
	@Test
	public void test017() throws Exception {
		// 記録フェーズ
		DateUtil dateMocked = spy(new DateUtil());
		PowerMockito.doThrow(new RuntimeException("aaa")).when(dateMocked, "getYYYYMMDDString", (Date) any());

		// リプレイ＆検証フェーズ
		try {
			dateMocked.getYYYYMMDDStringWrapper(new Date());
			fail();
		} catch (RuntimeException e) {
			assertThat(e.getMessage(), is("aaa"));
		}
	}

## No.18
	/**
	 * privateメソッド、戻り型はvoid、一部モック、例外を投げる
	 */
	@Test
	public void test018() throws Exception {
		// 記録フェーズ
		DateUtil dateMocked = spy(new DateUtil());
		PowerMockito.doThrow(new Exception("bbb")).when(dateMocked, "setFlag", anyBoolean());

		// リプレイ＆検証フェーズ
		Method setFlagMethod = DateUtil.class.getDeclaredMethod("setFlag", Boolean.class);
		setFlagMethod.setAccessible(true);
		try {
			setFlagMethod.invoke(dateMocked, true);
			fail();
		} catch (Exception e) {
			if (e instanceof InvocationTargetException) {
				InvocationTargetException ite = (InvocationTargetException) e;
				assertThat(ite.getTargetException().getMessage(), is("bbb"));
			} else {
				fail();
			}
		}
	}

# 参考
## Mockito
http://site.mockito.org/
## PowerMock
https://github.com/powermock/powermock
## 動作確認したプロジェクト
https://github.com/taka2/mockito-sample
## Mockito1xでのケース別モックのかけかた
https://qiita.com/taka_22/items/0c13aacf6ffbc2c77970