web-dev-qa-db-ja.com

Android-独立したフラグメントUIテストツール

フラグメントのUIを個別に(つまり、他のフラグメントやアクティビティから独立して)テストする方法を探していましたが、それを行う方法が見つかりません。

特に、フラグメントA、フラグメントB、フラグメントCがあるとします。フラグメントCに移動する唯一の方法(アプリごと)は、最初にフラグメントAとフラグメントBを通過することです。フラグメントAとBを通過せずに、フラグメントCを直接(依存関係が存在する場合はモックすることで)テストする方法を探しています。

これまでに調査したツール:

  • サル:コマンドラインから疑似ランダムイベントを生成するためにのみ使用されます。私が欲しいものではありません。

  • monkeyrunner:Pythonプログラムを実行して、イベントストリームを私のAndroidアプリに送信できますが、これらのスクリプトで特定のフラグメントを直接ターゲットにすることはできません。

  • Espresso:ホワイトボックステストツール。これは私が望むものに近づきますが、フラグメントCに到達する前にフラグメントAとBを通過する必要があります(つまり、アプリを起動する必要があり、そこからテストが実行されます)。

  • UI Automator:ブラックボックステストツール。これも近づいていますが、必要なフラグメント(フラグメントC)をテストする前に、前のフラグメントを通過する必要があります。

FragmenのUIをテストする tを直接行う方法はありますか?

20
Tiago

カスタムのFragmentTestRuleとEspressoを使用して、それぞれのFragmentsを個別にテストしています。

アプリでテスト済みのTestActivityを表示する専用のFragmentsがあります。私の場合、インストルメンテーションテストはActivityに対して実行されるため、debugdebugバリアントにのみ存在します。

TL; DR @ brais-gabin による素晴らしい FragmentTestRuleライブラリを使用します。

1。テストされたTestActivityが追加されるコンテンツビューを使用してsrc/debug/Java/your/package/TestActivity.JavaFragmentを作成します。

@VisibleForTesting
public class TestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FrameLayout frameLayout = new FrameLayout(this);
        frameLayout.setId(R.id.container);
        setContentView(frameLayout);
    }
}

2。 debugバリアントのAndroidManifest.xmlを作成し、TestActivityを宣言します。これは、テスト時にTestActivityを開始するために必要です。このマニフェストをsrc/debug/AndroidManifest.xmldebugバリアントに追加します。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <application>           
        <activity Android:name="your.package.TestActivity"/>
    </application>
</manifest>

3。 src/androidTest/Java/your/test/package/FragmentTestRule.JavaFragmentTestRuleバリアントにandroidTestを作成します。

public class FragmentTestRule<F extends Fragment> extends ActivityTestRule<TestActivity> {

    private final Class<F> mFragmentClass;
    private F mFragment;

    public FragmentTestRule(final Class<F> fragmentClass) {
        super(TestActivity.class, true, false);
        mFragmentClass = fragmentClass;
    }

    @Override
    protected void afterActivityLaunched() {
        super.afterActivityLaunched();

        getActivity().runOnUiThread(() -> {
            try {
                //Instantiate and insert the fragment into the container layout
                FragmentManager manager = getActivity().getSupportFragmentManager();
                FragmentTransaction transaction = manager.beginTransaction();
                mFragment = mFragmentClass.newInstance();
                transaction.replace(R.id.container, mFragment);
                transaction.commit();
            } catch (InstantiationException | IllegalAccessException e) {
                Assert.fail(String.format("%s: Could not insert %s into TestActivity: %s",
                        getClass().getSimpleName(),
                        mFragmentClass.getSimpleName(),
                        e.getMessage()));
            }
        });
    }
    public F getFragment(){
        return mFragment;
    }
}

4。次に、Fragmentsを個別にテストできます。

public class MyFragmentTest {

    @Rule
    public FragmentTestRule<MyFragment> mFragmentTestRule = new FragmentTestRule<>(MyFragment.class);

    @Test
    public void fragment_can_be_instantiated() {

        // Launch the activity to make the fragment visible 
        mFragmentTestRule.launchActivity(null);

        // Then use Espresso to test the Fragment
        onView(withId(R.id.an_id_in_the_fragment)).check(matches(isDisplayed()));
    }
}
53
thaussma

@ thaussmaのアイデア を使用して FragmentTestRule Andoridライブラリを開発しました。 Fragmentsを個別にテストできます。

これを追加する必要があります:

@Rule
public FragmentTestRule<?, FragmentWithoutActivityDependency> fragmentTestRule =
    FragmentTestRule.create(FragmentWithoutActivityDependency.class);

詳細はこちら

3
Brais Gabin

Robotium を使用できます。これはAndroid UIテスト用です。

2
Almett

ナビゲーションアーキテクチャコンポーネントを使用していて、アプリで単一のアクティビティアーキテクチャを使用している場合は、テストの開始時に(適切な引数を使用して)ターゲットフラグメントにディープリンクすることで、各フラグメントをすばやくテストできます。

例えば:

@Rule
@JvmField
var activityRule = ActivityTestRule(MainActivity::class.Java)

protected fun launchFragment(destinationId: Int,
                             argBundle: Bundle? = null) {
    val launchFragmentIntent = buildLaunchFragmentIntent(destinationId, argBundle)
    activityRule.launchActivity(launchFragmentIntent)
}

private fun buildLaunchFragmentIntent(destinationId: Int, argBundle: Bundle?): Intent =
        NavDeepLinkBuilder(InstrumentationRegistry.getInstrumentation().targetContext)
                .setGraph(R.navigation.navigation)
                .setComponentName(MainActivity::class.Java)
                .setDestination(destinationId)
                .setArguments(argBundle)
                .createTaskStackBuilder().intents[0]

destinationIdは、ナビゲーショングラフのフラグメント宛先IDです。フラグメントを起動する準備ができたら実行される呼び出しの例を次に示します。

launchFragment(R.id.target_fragment, targetBundle())

private fun targetBundle(): Bundle? {
    val bundle = Bundle()
    bundle.putString(ARGUMENT_ID, "Argument needed by fragment")
    return bundle
}

このようにすると、フラグメントが直接起動します。テストが機能する場合、これは、フラグメントがディープリンクされているときにアプリがクラッシュしないことを証明します。また、プロセスがシステムによって強制終了され、スタックを再構築してフラグメントを再起動しようとした場合でも、アプリが安定することを保証します。

1
Sean Blahovici