web-dev-qa-db-ja.com

Android JUnit Testing ...例外を予期する方法

組み込みのAndroid Junitテストフレームワークを使用していくつかのテストを記述しようとしています。例外がスローされることを期待しているテストで問題が発生しています。JUnitでは、テストメソッドの注釈は次のようになります。

@Test(expected = ArithmeticException.class)

ただし、Androidでは、このテストはArithmeticExceptionで失敗します。

Android実装はJUnit 3のサブセットにすぎず、@ Testアノテーション(@ SmallTest、@ MediumTest、または@LargeTestである必要があり、それらのどれも'expected = ..'パラメータを許可します)、これはかなり重要なテストのようであり、Androidテストフレームワークには、この機能がなければ深刻に欠けているようです。

注: JUnit jarをプロジェクトに追加し、注釈をテストメソッドに追加して、これをテストしました。 Androidフレームワーク(ランナー?)がそのアノテーションを探しておらず、単に無視しているため、アノテーションが完全に無視されるのはなぜでしょうか。基本的に、私はただ 'フレームワーク内でこれを行う正しい方法。

51
Gimbl

この種のテストの標準のju​​nit 3イディオムは次のとおりです。

public void testThatMethodThrowsException()
{
  try
  {
    doSomethingThatShouldThrow();
    Assert.fail("Should have thrown Arithmetic exception");
  }
  catch(ArithmeticException e)
  {
    //success
  }
}
66

JUnit4は、Android SDK( Android-test-kit を参照)から入手できます。)

更新:それは現在公式です d.Android.com

AndroidJUnitRunnerは、Android Support Test Libraryの一部であり、Android Support Repositoryを介してダウンロードできます。新しいランナーには、GoogleInstrumentationTestRunnerのすべての改善が含まれており、さらに機能が追加されています。

  • JUnit4サポート
  • インストルメンテーション、コンテキスト、バンドルの引数にアクセスするためのインストルメンテーションレジストリ
  • テストフィルター@SdkSupressおよび@RequiresDevice
  • テストのタイムアウト
  • テストのシャーディング
  • テスト実行ライフサイクルにフックするRunListenerサポート
  • アクティビティ監視メカニズムActivityLifecycleMonitorRegistry

したがって、予想される注釈を使用して JUnit4スタイルの例外テスト

@Test(expected= IndexOutOfBoundsException.class) 
public void empty() { 
     new ArrayList<Object>().get(0); 
}

または予期される例外ルール:

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
    List<Object> list = new ArrayList<Object>();

    thrown.expect(IndexOutOfBoundsException.class);
    thrown.expectMessage("Index: 0, Size: 0");
    list.get(0); // execution will never get past this line
}

も可能です。

テストサポートライブラリのセットアップ方法の詳細については、 公式ドキュメント を参照してください。

29
sandrstar

私はいくつかの良い解決策を探していましたが、どの解決策も本当に満足のいくものではありませんでした。それで、私は自分で作りました。

public final void assertThrows(VoidFunction v, Class<? extends Exception> e) {
    try {
        v.call();
    } catch (Exception ex) {
        if (!ex.getClass().equals(e)) {
            Assert.fail();
        }
        // Do nothing, basically succeeds test if same exception was thrown.
        return;
    }

    // Fails if no exception is thrown by default.
    Assert.fail();
}

VoidFunctionがシンプルなインターフェースである場合:

@FunctionalInterface
public interface VoidFunction {
    void call();
}

これは次のように使用されます(例):

@Test
public void testFoo() {
    assertThrows(() -> foo.bar(null)), NullPointerException.class);
    assertThrows(() -> foo.setPositiveInt(-5)), IllegalArgumentException.class);
    assertThrows(() -> foo.getObjectAt(-100)), IndexOutOfBoundsException.class);
    assertThrows(new VoidFunction() {
            @Override
            public void call() {
                foo.getObjectAt(-100);
            }
        }, IndexOutOfBoundsException.class); // Success
    assertThrows(new VoidFunction() {
                @Override
                public void call() {
                    throw new Exception();
                }
            }, NullPointerException.class); // Fail

}

ラムダを使用せずに1つの呼び出しを含めました。これにより、少なくとも私にとっては、コードを時々理解しやすくなります。使い方は簡単で、1つのメソッドで複数の例外キャッチが可能です。

2
Ludvig W