web-dev-qa-db-ja.com

Mockito-メソッドをスタブするときのNullpointerException

そこで、Java-Spring-projectのテストを書き始めました。

私が使用しているのは、JUnitとMockitoです。 when()... thenReturn()オプションを使用すると、シミュレートせずにサービスをモックできると言われています。だから私がやりたいことは、設定することです:

when(classIwantToTest.object.get().methodWhichReturnsAList(input))thenReturn(ListcreatedInsideTheTestClass)  

ただし、どのwhen句を使用しても、入力がnullであるため、当然のことながら、常にNullpointerExceptionが発生します。

また、オブジェクトから別のメソッドをモックしようとすると:

when(object.method()).thenReturn(true)

また、メソッドには設定されていない変数が必要なので、Nullpointerも取得します。

しかし、when().. thenReturn()を使用して、この変数の作成などを回避したいと思います。確認したいのは、クラスがこのメソッドを呼び出す場合、何があっても、trueまたは上記のリストを返すだけです。

それは基本的に私の側からの誤解ですか、それとも何か他に間違っていることはありますか?

コード:

public class classIWantToTest implements classIWantToTestFacade{
        @Autowired
        private SomeService myService;

        @Override
        public Optional<OutputData> getInformations(final InputData inputData) {
            final Optional<OutputData> data = myService.getListWithData(inputData);
            if (data.isPresent()) {
                final List<ItemData> allData = data.get().getItemDatas();
                    //do something with the data and allData
                return data;
            }

            return Optional.absent();
        }   
}

そして、これが私のテストクラスです。

public class Test {

    private InputData inputdata;

    private ClassUnderTest classUnderTest;

    final List<ItemData> allData = new ArrayList<ItemData>();

    @Mock
    private DeliveryItemData item1;

    @Mock
    private DeliveryItemData item2;



    @Mock
    private SomeService myService;


    @Before
    public void setUp() throws Exception {
        classUnderTest = new ClassUnderTest();
        myService = mock(myService.class); 
        classUnderTest.setService(myService);
        item1 = mock(DeliveryItemData.class);
        item2 = mock(DeliveryItemData.class);

    }


    @Test
    public void test_sort() {
        createData();
        when(myService.getListWithData(inputdata).get().getItemDatas());

        when(item1.hasSomething()).thenReturn(true);
        when(item2.hasSomething()).thenReturn(false);

    }

    public void createData() {
        item1.setSomeValue("val");
        item2.setSomeOtherValue("test");

        item2.setSomeValue("val");
        item2.setSomeOtherValue("value");

        allData.add(item1);
        allData.add(item2);


}
44
user5417542

まだスタブしていないメソッドのデフォルトの戻り値は、ブールメソッドの場合はfalse、コレクションまたはマップを返すメソッドの場合は空のコレクションまたはマップ、そうでない場合はnullです。

これは、when(...)内のメソッド呼び出しにも適用されます。あなたの例では、when(myService.getListWithData(inputData).get())nullであるため、myService.getListWithData(inputData)はNullPointerExceptionを引き起こします。

1つのオプションは、すべての中間戻り値のモックを作成し、使用前にそれらをスタブ化することです。例えば:

ListWithData listWithData = mock(ListWithData.class);
when(listWithData.get()).thenReturn(item1);
when(myService.getListWithData()).thenReturn(listWithData);

または、モックを作成するときに別のデフォルトの回答を指定して、メソッドがnullではなく新しいモックを返すようにすることもできます:RETURNS_DEEP_STUBS

SomeService myService = mock(SomeService.class, Mockito.RETURNS_DEEP_STUBS);
when(myService.getListWithData().get()).thenReturn(item1);

Mockito.RETURNS_DEEP_STUBS のJavadocを読む必要があります。これは、これをより詳細に説明し、その使用法についての警告もあります。

これがお役に立てば幸いです。サンプルコードには、assertまたはverifyステートメントの欠落や、モックでのセッターの呼び出し(効果はありません)など、より多くの問題があるように見えることに注意してください。

47
ahu

この問題があり、私の問題はany()ではなくanyInt()でメソッドを呼び出していたことでした。だから私は持っていた:

doAnswer(...).with(myMockObject).thisFuncTakesAnInt(any())

それを次のように変更しなければなりませんでした。

doAnswer(...).with(myMockObject).thisFuncTakesAnInt(anyInt())

それがNullPointerExceptionを生成した理由がわかりません。たぶん、これは次の貧しい魂を助けるでしょう。

88

私は同じ問題を抱えていましたが、私の問題は、単に@RunWithを使用してクラスに適切に注釈を付けなかったことです。あなたの例では、あなたが持っていることを確認してください:

@RunWith(MockitoJUnitRunner.class)
public class Test {
...

それをやると、NullPointerExceptionsが消えました。

38
Ed Webb

私にとってNPEを得た理由は、プリミティブをモックするときにMockito.any()を使用していたためです。 mockitoから正しいバリアントを使用するように切り替えると、エラーが取り除かれることがわかりました。

たとえば、any()を使用する代わりに、プリミティブlongをパラメーターとして取る関数をモックするには、より具体的にし、any(Long.class)またはMockito.anyLong()に置き換えます。

それが誰かを助けることを願っています。

6
smac89

将来の読者のために、モックを使用するときのNPEの別の原因は、次のようにモックを初期化することを忘れていることです:

@Mock
SomeMock someMock;

@InjectMocks
SomeService someService;

@Before
public void setup(){
    MockitoAnnotations.initMocks(this); //without this you will get NPE
}

@Test
public void someTest(){
    Mockito.when(someMock.someMethod()).thenReturn("some result");
   // ...
}

また、すべての注釈にJUnitを使用していることを確認してください。私はかつて誤ってtestNGから@Testを使用してテストを作成したため、@ Beforeは動作しませんでした(testNGではアノテーションは@BeforeTestです)

3
Tal Joffe

コーナーケース:
Scalaを使用していて、valueクラスでanyマッチャーを作成しようとする場合、役に立たないNPEを受け取ります。

case class ValueClass(value: Int) extends AnyValが与えられた場合、あなたがしたいことはany[ValueClass]の代わりにValueClass(anyInt)です

when(mock.someMethod(ValueClass(anyInt))).thenAnswer {
   ...
   val v  = ValueClass(invocation.getArguments()(0).asInstanceOf[Int])
   ...
}

この他の SOの質問 はそれについてより具体的ですが、値クラスに問題があることを知らない場合は見逃してしまいます。

3
Vituel
@RunWith(MockitoJUnitRunner.class) //(OR) PowerMockRunner.class

@PrepareForTest({UpdateUtil.class,Log.class,SharedPreferences.class,SharedPreferences.Editor.class})
public class InstallationTest extends TestCase{

@Mock
Context mockContext;
@Mock
SharedPreferences mSharedPreferences;
@Mock
SharedPreferences.Editor mSharedPreferenceEdtor;

@Before
public void setUp() throws Exception
{
//        mockContext = Mockito.mock(Context.class);
//        mSharedPreferences = Mockito.mock(SharedPreferences.class);
//        mSharedPreferenceEdtor = Mockito.mock(SharedPreferences.Editor.class);
    when(mockContext.getSharedPreferences(Mockito.anyString(),Mockito.anyInt())).thenReturn(mSharedPreferences);
    when(mSharedPreferences.edit()).thenReturn(mSharedPreferenceEdtor);
    when(mSharedPreferenceEdtor.remove(Mockito.anyString())).thenReturn(mSharedPreferenceEdtor);
    when(mSharedPreferenceEdtor.putString(Mockito.anyString(),Mockito.anyString())).thenReturn(mSharedPreferenceEdtor);
}

@Test
public void deletePreferencesTest() throws Exception {

 }
}

@ Mock Annotation to Context mockContext;を使用する場合、上記のすべてのコメント付きコードは必須ではありません{mockContext = Mockito.mock(Context.class);}

@Mock 
Context mockContext; 

ただし、@ RunWith(MockitoJUnitRunner.class)のみを使用する場合は機能します。 Mockitoに従って、@ MockまたはMockito.mock(Context.class);を使用してモックオブジェクトを作成できます。

@RunWith(PowerMockRunner.class)を使用しているためにNullpointerExceptionが発生しましたが、代わりに@RunWith(MockitoJUnitRunner.class)に変更しました。

1
anand krish

同じ問題、私のために働いた解決策に直面しました:

サービスインターフェイスをモックする代わりに、@ InjectMocksを使用してサービス実装をモックしました。

@InjectMocks
private exampleServiceImpl exampleServiceMock;

の代わりに :

@Mock
private exampleService exampleServiceMock;
0

私の場合、最初に追加できなかった

PowerMockito.spy(ClassWhichNeedToBeStaticMocked.class);

そのため、このようなエラーが発生した人にはこれが役立ちます

Java.lang.NullPointerException
    at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.addAnswersForStubbing(PowerMockitoStubberImpl.Java:67)
    at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.Java:42)
    at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.Java:112)
0

注釈付きフィールドを初期化するには、MockitoAnnotations.initMocks(this)メソッドを呼び出す必要があります。

   @Before public void initMocks() {
       MockitoAnnotations.initMocks(this);
   }

詳細については、 Doc を参照してください

0
Jacob

上記の回答のどれも私を助けませんでした。コードがJavaで機能する理由を理解するのに苦労しましたが、Kotlinではnotです。

それから私は this thread からそれを考え出した。

クラス関数とメンバー関数を作成する必要がありますopen、そうでない場合はNPEがスローされていました。

関数openを作成した後、テストに合格し始めました。

コンパイラの "all-open"プラグイン の使用を検討することもできます。

Kotlinにはデフォルトでクラスとそのメンバーfinalがあり、フレームワークやライブラリを使用するのは不便ですクラスがopenであることが必要なSpring AOPとして。 all-openコンパイラプラグインは、Kotlinをこれらのフレームワークの要件に適合させ、特定の注釈で注釈付けされたクラスとそのメンバーを明示的に開かずにopenにしますキーワード。

0
azizbekian

これらの答えはどれも私にとってはうまくいきませんでした。この回答はOPの問題を解決するものではありませんが、この投稿はこの問題をグーグルで表示する唯一のものであるため、ここで回答を共有しています。

Androidの単体テストを書いているときにこの問題に遭遇しました。問題は、私がテストしていたアクティビティがAppCompatActivityではなくActivityを拡張したことでした。これを修正するために、AppCompatActivityActivityに置き換えることができました。本当に必要なかったからです。これは誰にとっても実行可能なソリューションではないかもしれませんが、うまくいけば根本原因を知ることは誰かを助けるでしょう。

0
mindreader

Ed Webbの answer は私の場合に役立ちました。代わりに、追加することもできます

  @Rule public Mocks mocks = new Mocks(this);

@RunWith(JUnit4.class)の場合。

0
lcn