web-dev-qa-db-ja.com

android espressoログインしてテストを実行する前に1回

私は自分のAndroidアプリをテストでカバーし、 espresso最近 を使い始めました。これまでにかなり感銘を受けました。しかし、私のアプリの機能のほとんどは、すべてのテストが独立しているため、テストごとに新しいユーザーを登録する必要がありますが、これは正常に機能しますが、これにより各テストに必要な時間が大幅に増加します。

(テストの)クラスに一度ユーザーを登録し、その同じユーザーアカウントを使用してそのクラスのすべてのテストを実行する方法を見つけようとしています。

私がこれを行うことができた1つの方法は、実際に他のすべてのテストを必要な順序で実行する1つのテスト(@Test)メソッドのみを持つことです。ただし、これはオールオアナッシングアプローチです。gradle cATタスクは、成功/失敗した可能性のある中間テストに関する情報を提供せずに、最後に一度だけ結果を出力するためです。

私は@BeforeClassアプローチも試してみましたが、機能しませんでした(デバッグオプションを使用してもこれを使用したクラスからのgradle出力はなく、次のクラスに進むまでに長い時間がかかったようです)テスト)。

クラスの開始時に一度ユーザーを登録し、テストの最後に一度ログアウトするより良いアプローチはありますか?

助けてくれてありがとう。

30
source.rar

理想的には、さまざまなログイン/ログアウトシナリオをテストする一連のテストでログイン/ログアウト機能をテストし、他のテストでは他の使用例に焦点を当てます。ただし、他のシナリオはログインしているユーザーに依存するため、これを解決する1つの方法は、ログインを処理するアプリコンポーネントのモックバージョンを提供することです。他のログイン依存テストの場合、このモックを最初に挿入すると、アプリの残りの部分で使用できる模擬ユーザー認証情報が返されます。

これを実現するためにDagger、Mockito、Espressoが使用されている例を次に示します。 https://engineering.circle.com/instrumentation-testing-with-dagger-mockito-and-espresso/

11
fejd

私はこれと同じシナリオを必要とするアプリをテストします。私がこれを回避した最も簡単な方法は、ログインとログアウトを独自のテストクラスに分割することです。次に、すべてのテストクラスをスイートに追加し、ログインスイートとログアウトスイートでそれぞれ開始および終了します。あなたのテストスイートは、このようなものになってしまいます。

@RunWith(Suite.class)
@Suite.SuiteClasses({
        LoginSetup.class,
        SmokeTests.class,
        LogoutTearDown.class
})

編集:これは、LoginSetupテストとLogoutTearDownテストの両方の例です。このソリューションは、実際にはエンドツーエンドのテストのみを対象とし、テスト作業のごく一部を構成する必要があります。 fejdは解決策を提供します 検討する必要がある完全なテストスタック用.

@LargeTest
public class SmokeSetup extends LogInTestFixture {

    @Rule
    public ActivityTestRule<LoginActivity> mLoginActivity = new ActivityTestRule<>(LoginActivity.class);

    @Test
    public void testSetup() throws IOException {

        onView(withId(R.id.username_field)).perform(replaceText("username"));
        onView(withId(R.id.password_field)).perform(replaceText("password"));
        onView(withId(R.id.login_button)).perform(click());

    }

}

@LargeTest
public class LogoutTearDown extends LogInTestFixture {

    @Rule
    public ActivityTestRule<MainActivity> mMainActivity = new ActivityTestRule<>(MainActivity.class);

    @Test
    public void testLogout() throws IOException {

        onView(withId(R.id.toolbar_menu)).perform(click());
        onView(withId(R.id.logout_button)).perform(click());

    }

}
6
James Pullar

@Beforeを使用してログインするアプローチはいいですが、ログインが遅い場合、テストの合計時間が非常に遅くなります。

これが機能する素晴らしいハックです。戦略は単純です。すべてのテストを順番に実行し、特定のテスト(この場合はログインテスト)が失敗した場合に実行する前にすべてのテストを失敗させます。

@RunWith(AndroidJUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@LargeTest
public class YourTestsThatDependsOnLogin {

    private static failEverything;

    @Before
    public void beforeTest() {

        // Fail every test before it has a chance to run if login failed
        if (failEverything) {
            Assert.fail("Login failed so every test should fail");
        }

    }    

    @Test
    public void test0_REQUIREDTEST_login() {

        failEverything = true;
        // Your code for login
        // Your login method must fail the test if it fails.
        login();
        failEverything = false; // We are safe to continue.

    }

    // test1 test2 test3 etc...

}

長所:

  • あなたが求めたことはうまくいき、それは速いです(あなたのログインが遅い場合)
  • 異なるログインに依存する複数のテストを行うことができます。つまり、user1の一連のテストを実行してから、user2の一連のテストを実行できます。
  • セットアップが簡単。

短所:

  • 標準的な手順ではなく、なぜ多くのテストが失敗するのか不思議に思うかもしれません...
  • 実際にログインする代わりに、shouldユーザーを模擬します。あなたshouldのテスト個別にログインすると、テストが互いに依存してはなりません。
3
Erik Sillén

次の関数をテストファイルに追加し、tryブロックのコードを、ログインアクションを実行するコードに置き換えます。

@Before
fun setUp() {
    // Login if it is on the LoginActivity
    try {
        // Type email and password
        Espresso.onView(ViewMatchers.withId(R.id.et_email))
                .perform(ViewActions.typeText("a_test_account_username"), ViewActions.closeSoftKeyboard())
        Espresso.onView(ViewMatchers.withId(R.id.et_password))
                .perform(ViewActions.typeText("a_test_account_password"), ViewActions.closeSoftKeyboard())

        // Click login button
        Espresso.onView(ViewMatchers.withId(R.id.btn_login)).perform(ViewActions.click())
    } catch (e: NoMatchingViewException) {
        //view not displayed logic
    }
}

この@Beforeアノテーションを使用すると、このsetUp関数は、このテストファイルにある他のテストの前に実行されます。アプリがログインアクティビティに到達した場合は、このsetUp関数でログインします。ここの例では、電子メールとパスワードのEditText、およびログインボタンがあると想定しています。 Expressoを使用して電子メールとパスワードを入力し、ログインボタンを押します。 try catchブロックは、ログインアクティビティに到達していない場合にエラーをキャッチして何もしないことを確認するためのものです。ログインアクティビティに到達しなかった場合は、とにかく他のテストに進むことをお勧めします。

注:これはKotlinコードですが、Javaとよく似ています。

3
s-hunter

私のアプリケーションでも、ユーザーはテスト実行全体を通してログインする必要があります。ただし、初めてログインすることはでき、アプリケーションはテスト実行中、ユーザー名/パスワードを記憶しています。実際、私はそれらを忘れたり、アプリをアンインストールして再度インストールしたりするまで、資格情報を記憶しています。

テスト実行中、すべてのテストの後に、アプリがバックグラウンドになり、次のテストの開始時に再び再開されます。私はあなたのアプリケーションがバックグラウンドから前面に持ってくるたびにユーザーに資格情報を入力することを要求していると思います(おそらく銀行アプリケーション?)。アプリケーションに「資格情報を記憶する」設定がありますか?はいの場合は、テスト実行で初めてログインした直後に簡単に有効にできます。

それ以外は、資格情報を覚えておく方法を提供することについて開発者と話し合う必要があると思います。

2
drfrag01