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

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

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

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

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

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

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

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

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

何か方法はあるでしょうかフラグメントのUIをテストする直接ですか?

ベストアンサー1

私はカスタムFragmentTestRuleとエスプレッソを使用して、それぞれをFragments個別にテストしています。

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

TL;DR 素晴らしいフラグメントテストルールライブラリブレイス・ガビン

1. 作成するTestActivityテストされた内容が追加されるsrc/debug/java/your/package/TestActivity.javaコンテンツ ビューで次のようになります。Fragment

@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. AndroidManifest.xmlを作成するdebugバリアントに対してを宣言しますTestActivity。これは、テスト時に を開始するために必要です。のバリアントTestActivityにこのマニフェストを追加します。debugsrc/debug/AndroidManifest.xml

<?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. 作成するFragmentTestRuleバリアントでは次androidTestのようになりますsrc/androidTest/java/your/test/package/FragmentTestRule.java:

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()));
    }
}

おすすめ記事