組み込みのAndroid Junitテストフレームワークを使用していくつかのテストを記述しようとしています。例外がスローされることを期待しているテストで問題が発生しています。JUnitでは、テストメソッドの注釈は次のようになります。
@Test(expected = ArithmeticException.class)
ただし、Androidでは、このテストはArithmeticExceptionで失敗します。
Android実装はJUnit 3のサブセットにすぎず、@ Testアノテーション(@ SmallTest、@ MediumTest、または@LargeTestである必要があり、それらのどれも'expected = ..'パラメータを許可します)、これはかなり重要なテストのようであり、Androidテストフレームワークには、この機能がなければ深刻に欠けているようです。
注: JUnit jarをプロジェクトに追加し、注釈をテストメソッドに追加して、これをテストしました。 Androidフレームワーク(ランナー?)がそのアノテーションを探しておらず、単に無視しているため、アノテーションが完全に無視されるのはなぜでしょうか。基本的に、私はただ 'フレームワーク内でこれを行う正しい方法。
この種のテストの標準のjunit 3イディオムは次のとおりです。
public void testThatMethodThrowsException()
{
try
{
doSomethingThatShouldThrow();
Assert.fail("Should have thrown Arithmetic exception");
}
catch(ArithmeticException e)
{
//success
}
}
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
}
も可能です。
テストサポートライブラリのセットアップ方法の詳細については、 公式ドキュメント を参照してください。
私はいくつかの良い解決策を探していましたが、どの解決策も本当に満足のいくものではありませんでした。それで、私は自分で作りました。
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つのメソッドで複数の例外キャッチが可能です。