Android: 为 Fragments 编写测试用例

Android: Writing test cases for Fragments

在我以前的项目中,我通过活动完成了大部分工作,并根据文档使用了 ActivityInstrumentationTestCase2:
http://developer.android.com/tools/testing/activity_testing.html
我知道如何使用 Activity 个测试用例;但是说到 Fragment ,我没有太多的想法,也没有找到很多相关的文档。 那么当我有几个具有一两个活动的片段时如何编写测试用例呢? 任何示例代码或样本都会更有帮助。

这是使用 ActivityInstrumentationTestCase2 的粗略指南:

步骤 1。创建一个空白 Activity 来保存您的片段

  private static class FragmentUtilActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      LinearLayout view = new LinearLayout(this);
      view.setId(1);

      setContentView(view);
    }
  }

第 2 步: 在您的测试中,实例化您的片段并将其添加到空白 activity

public class MyFragmentTest extends ActivityInstrumentationTestCase2<FragmentUtilActivity> { 
    private MyFragment fragment;

    @Before
    public void setup() {
        fragment = new MyFragment();
        getActivity().getFragmentManager().beginTransaction().add(1, fragment, null).commit();
    }
}

步骤 3 测试您的实例化片段

@Test
public void aTest() {
    fragment.getView().findViewById(...);
}

如果您使用 robolectric,使用 FragmentUtilTest class:

非常简单
@Test
public void aTest() {
    // instantiate your fragment
    MyFragment fragment = new MyFragment();

    // Add it to a blank activity
    FragmentTestUtil.startVisibleFragment(fragment);

    // ... call getView().findViewById() on your fragment
}

使用您的主要 activity 作为发送到 ActivityInstrumentationTestCase2 的测试 activity。然后,您可以通过启动片段的主要 activity 的片段管理器来处理片段。这甚至比测试 activity 更好,因为它使用您在主 activity 中编写的逻辑来测试场景,从而提供更全面和更完整的测试。

示例:

public class YourFragmentTest extends ActivityInstrumentationTestCase2<MainActivity> {  
    public YourFragmentTest(){
            super(MainActivity.class);
        }

}

这是我的工作解决方案:

  1. 在 androidTest 目录中为此创建一个检测单元测试 class,即:

    public class FragmentTest extends 
    ActivityInstrumentationTestCase2<MainActivity> {
         private MainActivity testingActivity;
         private TestFragment testFragment;
         //... 
    }
    
  2. 在这个新的 class:

    中调用这个构造函数
    public FragmentTest() {
    
        super(MainActivity.class);
    }
    
  3. 重写 setUp() 方法(确保 R.id.fragmentContainer 在你的 Activity class 中)你将在最后调用 waitForIdleSync():

    @Override
    protected void setUp() throws Exception {
        super.setUp();
    
        // Starts the activity under test using
        // the default Intent with:
        // action = {@link Intent#ACTION_MAIN}
        // flags = {@link Intent#FLAG_ACTIVITY_NEW_TASK}
        // All other fields are null or empty.
        testingActivity = getActivity();
    
        testFragment = new TestFragment();
        testingActivity.getFragmentManager().beginTransaction().add(R.id.fragmentContainer,testFragment,null).commit();
        /**
         * Synchronously wait for the application to be idle.  Can not be called
         * from the main application thread -- use {@link #start} to execute
         * instrumentation in its own thread.
         *
         * Without waitForIdleSync(); our test would have nulls in fragment references.
         */
        getInstrumentation().waitForIdleSync();
    }
    
  4. 写一个测试方法,例如:

    public void testGameFragmentsTextViews() {
    
       String empty = "";
       TextView textView = (TextView)testFragment.getView().findViewById(R.id.myTextView);
       assertTrue("Empty stuff",(textView.getText().equals(empty)));   
    }
    
  5. 运行 测试.

现在 ActivityInstrumentationTestCase2 已弃用。现在您可以使用规则在测试中使用活动:http://wiebe-elsinga.com/blog/whats-new-in-android-testing/

为了使这些工作正常,您必须添加依赖项 build.gradle:

testCompile 'com.android.support.test:rules:0.5'
testCompile 'com.android.support.test:runner:0.5'

(见

AndroidX 提供了一个库,FragmentScenario,用于创建片段并更改它们的状态。

app/build.gradle

dependencies {
    def fragment_version = "1.0.0"
    // ...
    debugImplementation 'androidx.fragment:fragment-testing:$fragment_version'
}

例子

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        // The "fragmentArgs" and "factory" arguments are optional.
        val fragmentArgs = Bundle().apply {
            putInt("selectedListItem", 0)
        }
        val factory = MyFragmentFactory()
        val scenario = launchFragmentInContainer<MyFragment>(
                fragmentArgs, factory)
        onView(withId(R.id.text)).check(matches(withText("Hello World!")))
    }
}

更多信息在 official docs