フラグメントの 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
内には のみ存在します。debug
debug
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
にこのマニフェストを追加します。debug
src/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()));
}
}