そこで、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);
}
まだスタブしていないメソッドのデフォルトの戻り値は、ブールメソッドの場合は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ステートメントの欠落や、モックでのセッターの呼び出し(効果はありません)など、より多くの問題があるように見えることに注意してください。
この問題があり、私の問題はany()
ではなくanyInt()
でメソッドを呼び出していたことでした。だから私は持っていた:
doAnswer(...).with(myMockObject).thisFuncTakesAnInt(any())
それを次のように変更しなければなりませんでした。
doAnswer(...).with(myMockObject).thisFuncTakesAnInt(anyInt())
それがNullPointerExceptionを生成した理由がわかりません。たぶん、これは次の貧しい魂を助けるでしょう。
私は同じ問題を抱えていましたが、私の問題は、単に@RunWithを使用してクラスに適切に注釈を付けなかったことです。あなたの例では、あなたが持っていることを確認してください:
@RunWith(MockitoJUnitRunner.class)
public class Test {
...
それをやると、NullPointerExceptionsが消えました。
私にとってNPEを得た理由は、プリミティブをモックするときにMockito.any()
を使用していたためです。 mockitoから正しいバリアントを使用するように切り替えると、エラーが取り除かれることがわかりました。
たとえば、any()
を使用する代わりに、プリミティブlong
をパラメーターとして取る関数をモックするには、より具体的にし、any(Long.class)
またはMockito.anyLong()
に置き換えます。
それが誰かを助けることを願っています。
将来の読者のために、モックを使用するときの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です)
コーナーケース:
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の質問 はそれについてより具体的ですが、値クラスに問題があることを知らない場合は見逃してしまいます。
@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)に変更しました。
同じ問題、私のために働いた解決策に直面しました:
サービスインターフェイスをモックする代わりに、@ InjectMocksを使用してサービス実装をモックしました。
@InjectMocks
private exampleServiceImpl exampleServiceMock;
の代わりに :
@Mock
private exampleService exampleServiceMock;
私の場合、最初に追加できなかった
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)
注釈付きフィールドを初期化するには、MockitoAnnotations.initMocks(this)メソッドを呼び出す必要があります。
@Before public void initMocks() {
MockitoAnnotations.initMocks(this);
}
詳細については、 Doc を参照してください
上記の回答のどれも私を助けませんでした。コードがJavaで機能する理由を理解するのに苦労しましたが、Kotlinではnotです。
それから私は this thread からそれを考え出した。
クラス関数とメンバー関数を作成する必要がありますopen
、そうでない場合はNPEがスローされていました。
関数open
を作成した後、テストに合格し始めました。
コンパイラの "all-open"プラグイン の使用を検討することもできます。
Kotlinにはデフォルトでクラスとそのメンバーfinalがあり、フレームワークやライブラリを使用するのは不便ですクラスがopenであることが必要なSpring AOPとして。
all-open
コンパイラプラグインは、Kotlinをこれらのフレームワークの要件に適合させ、特定の注釈で注釈付けされたクラスとそのメンバーを明示的に開かずにopenにしますキーワード。
これらの答えはどれも私にとってはうまくいきませんでした。この回答はOPの問題を解決するものではありませんが、この投稿はこの問題をグーグルで表示する唯一のものであるため、ここで回答を共有しています。
Androidの単体テストを書いているときにこの問題に遭遇しました。問題は、私がテストしていたアクティビティがAppCompatActivity
ではなくActivity
を拡張したことでした。これを修正するために、AppCompatActivity
をActivity
に置き換えることができました。本当に必要なかったからです。これは誰にとっても実行可能なソリューションではないかもしれませんが、うまくいけば根本原因を知ることは誰かを助けるでしょう。
Ed Webbの answer は私の場合に役立ちました。代わりに、追加することもできます
@Rule public Mocks mocks = new Mocks(this);
@RunWith(JUnit4.class)
の場合。