Mockito+PowerMockで不可視メソッドをspy

目的

privateメソッドやパッケージ違いの親クラスのprotectedメソッドのようにテストコードから不可視なメソッドにspyを適用したい。

方法

PowerMockito.whenを使う。

Target target = PowerMockito.spy(new Target());
PowerMockito.when(target, "invisibleMethod", "hoge").thenReturn("mock-string");


(参考:Mockitoのspy)

Target target = Mockito.spy(new Target());
Mockito.when(target.method("hoge")).thenReturn("mock-string");

検証

いろんな不可視パターンで試してみる

ソースコード

テスト対象クラス
package kurukuruz.test.mock;

import kurukuruz.test.mock.base.Parent;

public class Target extends Parent {

    public String executeOwnMethod(){
        return "own method return: " + private1();
    }

    private String private1() {
        return "own";
    }

    public String executeParent1() {
        return "method1 return: " + method1();
    }

    public String executeParent2() {
        return "method2 return: " + method2();
    }

    public String executeParent3() {
        return "method3 return: " + method3();
    }

    public String executeParent4(String hoge) {
        return "method4 return: " + method4(hoge);
    }

    public String executeParent5(Dao dao) throws Exception {
        return "method5 return: " + method5(dao);
    }

}
親クラス
package kurukuruz.test.mock.base;

import lombok.Getter;
import lombok.Setter;

public class Parent {

    /** publicメソッド */
    public String method1() {
        return "method1";
    }

    /** protectedメソッド */
    protected String method2() {
        return "method2";
    }

    /** protected finalメソッド */
    protected final String method3() {
        return "method3";
    }

    /** 引数あり(文字列) */
    protected final String method4(String hoge) {
        return hoge;
    }

    /** 引数が任意のオブジェクト */
    protected final String method5(Dao dao) throws Exception {
        if(dao.getName() == null) {
            throw new Exception("name is null!");
        }
        return dao.getName();
    }

    @Setter
    @Getter
    public static class Dao {
        private String name;
    }
}

テストコード

package kurukuruz.test.mock;

import kurukuruz.test.mock.base.Parent.Dao;

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(Enclosed.class)
public class TargetTest {

    public static class そのまま実行 {

        @BeforeClass
        public static void setupBeforeClass() {
            System.out.println("---そのまま実行---");
        }

        @Test
        public void テスト0() throws Exception{
            Target t = new Target();
            System.out.println(t.executeOwnMethod());
        }

        @Test
        public void テスト1() throws Exception{
            Target t = new Target();
            System.out.println(t.executeParent1());
        }

        @Test
        public void テスト2() throws Exception{
            Target t = new Target();
            System.out.println(t.executeParent2());
        }

        @Test
        public void テスト3() throws Exception{
            Target t = new Target();
            System.out.println(t.executeParent3());
        }

        @Test
        public void テスト4() throws Exception{
            Target t = new Target();
            System.out.println(t.executeParent4("hoge"));
        }

        @Test
        public void テスト5() throws Exception{
            Target t = new Target();
            Dao param1 = new Dao();
            param1.setName("foo");
            System.out.println(t.executeParent5(param1));
        }
    }

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({Target.class})
    public static class モック実行 {

        @BeforeClass
        public static void setupBeforeClass() {
            System.out.println("---モック実行---");
        }

        @Test
        public void テスト0() throws Exception{
            Target t2 = PowerMockito.spy(new Target());
            PowerMockito.when(t2, "private1").thenReturn("mock0");
            System.out.println(t2.executeOwnMethod());
        }

        @Test
        public void テスト1() throws Exception {
            Target t2 = PowerMockito.spy(new Target());
            PowerMockito.when(t2, "method1").thenReturn("mock1");
            System.out.println(t2.executeParent1());
        }

        @Test
        public void テスト2() throws Exception {
            Target t2 = PowerMockito.spy(new Target());
            PowerMockito.when(t2, "method2").thenReturn("mock2");
            System.out.println(t2.executeParent2());
        }

        @Test
        public void テスト3() throws Exception {
            Target t2 = PowerMockito.spy(new Target());
            PowerMockito.when(t2, "method3").thenReturn("mock3");
            System.out.println(t2.executeParent3());
        }

        @Test
        public void テスト4() throws Exception {
            Target t2 = PowerMockito.spy(new Target());
            PowerMockito.when(t2, "method4", "hoge").thenReturn("mock4");
            System.out.println(t2.executeParent4("hoge"));
            System.out.println(t2.executeParent4("foo"));
        }

        @Test
        public void テスト5() throws Exception {
            Target t2 = PowerMockito.spy(new Target());
            Dao dao = new Dao();
            dao.setName("bar");
            PowerMockito.when(t2, "method5", dao).thenReturn("mock5");
            System.out.println(t2.executeParent5(dao));
        }
    }
}

実行結果

---そのまま実行---
own method return own
method1 return method1
method2 return method2
method3 return method3
method4 return hoge
method5 return foo
---モック実行---
method4 return mock4
method4 return foo
method1 return mock1
own method return mock0
method2 return mock2
method3 return mock3
method5 return mock5

参考サイト