web-dev-qa-db-ja.com

PowerMockitoモック静的メソッドがパラメーターのメソッドを呼び出すと失敗する

いくつかの静的メソッドを持つ電卓クラスを使用するクラスをテストしようとしています。同様の方法で別のクラスのモックを作成しましたが、これはより頑固であることを証明しています。

モックされたメソッドに、渡された引数の1つに対するメソッド呼び出しが含まれている場合、静的メソッドはモックされていない(そしてテストが中断している)ようです。内部通話を削除することは明らかに選択肢ではありません。ここで私が見逃している明らかなものはありますか?

これは同じように動作する圧縮バージョンです...

public class SmallCalculator {

    public static int getLength(String string){

        int length = 0;

        //length = string.length(); // Uncomment this line and the mocking no longer works... 

        return length;
    }
}

そしてここにテストがあります...

import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;

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

import com.solveit.aps.transport.model.impl.SmallCalculator;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ SmallCalculator.class})
public class SmallTester {

    @Test
    public void smallTest(){

        PowerMockito.spy(SmallCalculator.class);
        given(SmallCalculator.getLength(any(String.class))).willReturn(5);

        assertEquals(5, SmallCalculator.getLength(""));
    }
}

質問にはいくつかの混乱があるようですので、もっと「現実的な」例を考案しました。これは間接レベルを追加しているので、モックされたメソッドを直接テストしているようには見えません。 SmallCalculatorクラスは変更されていません。

public class BigCalculator {

    public int getLength(){

        int length  = SmallCalculator.getLength("random string");

        // ... other logic

        return length;
    }

    public static void main(String... args){

        new BigCalculator();
    }
}

そして、ここに新しいテストクラスがあります...

import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;

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

import com.solveit.aps.transport.model.impl.BigCalculator;
import com.solveit.aps.transport.model.impl.SmallCalculator;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ SmallCalculator.class})
public class BigTester {

    @Test
    public void bigTest(){

        PowerMockito.spy(SmallCalculator.class);
        given(SmallCalculator.getLength(any(String.class))).willReturn(5);

        BigCalculator bigCalculator = new BigCalculator();
        assertEquals(5, bigCalculator.getLength());
    }
}
8
maccaroo

私はここで答えを見つけました https://blog.codecentric.de/en/2011/11/testing-and-mocking-of-static-methods-in-Java/

これが動作する最終的なコードです。私はこの方法を元のコード(および考案された例)でテストしましたが、うまく機能します。シンプル...

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;

import org.junit.Test;
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(PowerMockRunner.class)
@PrepareForTest({ SmallCalculator.class})
public class BigTester {

    @Test
    public void bigTest(){

        PowerMockito.mockStatic(SmallCalculator.class);
        PowerMockito.when(SmallCalculator.getLength(any(String.class))).thenReturn(5);

        BigCalculator bigCalculator = new BigCalculator();
        assertEquals(5, bigCalculator.getLength());
    }
}
17
maccaroo

anyString()の代わりにany(String.class)を使用してください。

any(String.class)を使用する場合、Mockitoは参照タイプのデフォルト値であるnullを返すため、渡される引数はnullです。その結果、例外が発生します。

anyString()を使用する場合、渡される引数は空の文字列になります。

これは例外が発生する理由を説明していますが、他のコメントや回答で説明されているように、メソッドのテスト方法を確認する必要があります。

1
vtor

まず、その行を削除します。

given(SmallCalculator.getLength(any(String.class))).willReturn(5);

同じメソッドをテストしているので。テストするメソッドをモックしたくない。

次に、アノテーションを次のように変更します。

@PrepareForTest({ SmallCalculator.class, String.class})

最後に、length();のモックを追加します。このような:

given(String.length()).willReturn(5);

私はそれでうまくいくと思います;)

1
JFPicard

その実際のメソッドが呼び出されたくない場合。の代わりに

_when(myMethodcall()).thenReturn(myResult);
_

使用する

_doReturn(myResult).when(myMethodCall());
_

それはあざける魔法であり、それが実際に機能する理由を説明することは困難です。

あなたが忘れた他のものはmockStatic(SmallCalculator.class)です

そして、あなたはPowerMockito.spy(SmallCalculator.class);を必要としません

0
talex