【问题标题】:How to set Unit Test to Fragment in Android如何在 Android 中将单元测试设置为片段
【发布时间】:2012-01-02 04:41:48
【问题描述】:

我想对一个 Android Fragment 类进行单元测试。

我可以使用 AndroidTestCase 设置测试还是需要使用 ApplicationTestCase?

是否有任何有用的示例说明如何使用这两个测试用例?开发者网站上的测试示例很少,似乎只专注于测试活动。

我在其他地方找到的所有示例都是扩展了 AndroidTestCase 类的示例,但所有测试的只是将两个数字相加,或者如果使用 Context,它只是执行简单的获取并测试某些内容不为空!

据我了解,Fragment 必须存在于 Activity 中。那么我可以创建一个模拟 Activity,还是让 Application 或 Context 提供一个可以测试 Fragment 的 Activity?

我是否需要创建自己的 Activity,然后使用 ActivityUnitTestCase?

【问题讨论】:

    标签: android unit-testing android-fragments fragment activityunittestcase


    【解决方案1】:

    我在同一个问题上苦苦挣扎。特别是,由于大多数代码示例已经过时 + Android Studio/SDK 正在改进,所以旧的答案有时不再相关。

    因此,首先要做的是:您需要确定是要使用 Instrumental 还是简单的 JUnit 测试。

    S.D. 精美地描述了它们之间的区别。 here; 简而言之:JUnit 测试更轻量级,不需要模拟器来运行,Instrumental - 为您提供最接近实际设备的可能体验(传感器、gps、与其他应用程序的交互等)。另请阅读有关testing in Android 的更多信息。

    1。片段的 JUnit 测试

    假设您不需要繁重的工具测试,简单的 junit 测试就足够了。 为此,我使用了不错的框架Robolectric

    在 gradle 中添加:

    dependencies {
        .....
        testCompile 'junit:junit:4.12'
        testCompile 'org.robolectric:robolectric:3.0'
        testCompile "org.mockito:mockito-core:1.10.8"
        testCompile ('com.squareup.assertj:assertj-android:1.0.0') {
            exclude module: 'support-annotations'
        }
        .....
    }
    

    Mockito、AsserJ 是可选的,但我发现它们非常有用,所以我强烈建议也包括它们。

    然后在 Build Variants 中将 Unit Tests 指定为 Test Artifact

    现在是时候编写一些真正的测试了 :-) 以标准的“Blank Activity with Fragment”示例项目为例。

    我添加了几行代码,以便实际测试:

    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivityFragment extends Fragment {
    
        private List<Cow> cows;
        public MainActivityFragment() {}
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {   
            cows = new ArrayList<>();
            cows.add(new Cow("Burka", 10));
            cows.add(new Cow("Zorka", 9));
            cows.add(new Cow("Kruzenshtern", 15));
    
            return inflater.inflate(R.layout.fragment_main, container, false);
        }
    
        int calculateYoungCows(int maxAge) {
            if (cows == null) {
                throw new IllegalStateException("onCreateView hasn't been called");
            }
    
            if (getActivity() == null) {
                throw new IllegalStateException("Activity is null");
            }
    
            if (getView() == null) {
                throw new IllegalStateException("View is null");
            }
    
            int result = 0;
            for (Cow cow : cows) {
                if (cow.age <= maxAge) {
                    result++;
                }
            }
    
            return result;
        }
    }
    

    还有牛班:

    public class Cow {
        public String name;
        public int age;
    
        public Cow(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    

    Robolectic 的测试集如下所示:

    import android.app.Application;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.test.ApplicationTestCase;
    
    import junit.framework.Assert;
    
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.robolectric.Robolectric;
    import org.robolectric.RobolectricGradleTestRunner;
    import org.robolectric.annotation.Config;
    
    import static org.assertj.core.api.Assertions.assertThat;
    import static org.mockito.Mockito.mock;
    import static org.mockito.Mockito.when;
    
    @RunWith(RobolectricGradleTestRunner.class)
    @Config(constants = BuildConfig.class, sdk=21)
    public class MainActivityFragmentTest extends ApplicationTestCase<Application> {
    
        public MainActivityFragmentTest() {
            super(Application.class);
        }
    
        MainActivity mainActivity;
        MainActivityFragment mainActivityFragment;
    
        @Before
        public void setUp() {
            mainActivity = Robolectric.setupActivity(MainActivity.class);
            mainActivityFragment = new MainActivityFragment();
            startFragment(mainActivityFragment);
        }
    
        @Test
        public void testMainActivity() {
            Assert.assertNotNull(mainActivity);
        }
    
        @Test
        public void testCowsCounter() {
            assertThat(mainActivityFragment.calculateYoungCows(10)).isEqualTo(2);
            assertThat(mainActivityFragment.calculateYoungCows(99)).isEqualTo(3);
        }
    
        private void startFragment( Fragment fragment ) {
            FragmentManager fragmentManager = mainActivity.getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.add(fragment, null );
            fragmentTransaction.commit();
        }
    }
    

    即我们通过 Robolectric.setupActivity 创建活动,这是测试类的 setUp() 中的新片段。或者,您可以立即从 setUp() 启动片段,也可以直接从测试中启动。

    NB!我没有花太多时间,但看起来几乎不可能和Dagger绑定在一起(我不知道是否使用 Dagger2 更容易),因为您无法使用模拟注入设置自定义测试应用程序。

    2。碎片的仪器测试

    这种方法的复杂性很大程度上取决于您是否在要测试的应用中使用 Dagger/Dependency 注入。

    Build Variants 中将 Android Instrumental Tests 指定为 Test Artifact

    在 Gradle 中,我添加了这些依赖项:

    dependencies {
        .....
        androidTestCompile "com.google.dexmaker:dexmaker:1.1"
        androidTestCompile "com.google.dexmaker:dexmaker-mockito:1.1"
        androidTestCompile 'com.squareup.assertj:assertj-android:1.0.0'
        androidTestCompile "org.mockito:mockito-core:1.10.8"
        }
        .....
    }
    

    (同样,几乎所有这些都是可选的,但它们可以让您的生活变得更轻松)

    - 如果你没有匕首

    这是一条快乐的道路。与上述 Robolectric 的区别仅在于小细节。

    准备步骤 1:如果您要使用 Mockito,您必须使用此 hack 使其能够在设备和模拟器上运行:

    public class TestUtils {
        private static final String CACHE_DIRECTORY = "/data/data/" + BuildConfig.APPLICATION_ID + "/cache";
        public static final String DEXMAKER_CACHE_PROPERTY = "dexmaker.dexcache";
    
        public static void enableMockitoOnDevicesAndEmulators() {
            if (System.getProperty(DEXMAKER_CACHE_PROPERTY) == null || System.getProperty(DEXMAKER_CACHE_PROPERTY).isEmpty()) {
                File file = new File(CACHE_DIRECTORY);
                if (!file.exists()) {
                    final boolean success = file.mkdirs();
                    if (!success) {
                        fail("Unable to create cache directory required for Mockito");
                    }
                }
    
                System.setProperty(DEXMAKER_CACHE_PROPERTY, file.getPath());
            }
        }
    }
    

    MainActivityFragment 和上面一样。所以测试集看起来像:

    package com.klogi.myapplication;
    
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.test.ActivityInstrumentationTestCase2;
    
    import junit.framework.Assert;
    
    import static org.assertj.core.api.Assertions.assertThat;
    import static org.mockito.Mockito.mock;
    import static org.mockito.Mockito.when;
    
    public class MainActivityFragmentTest extends ActivityInstrumentationTestCase2<MainActivity> {
    
        public MainActivityFragmentTest() {
            super(MainActivity.class);
        }
    
        MainActivity mainActivity;
        MainActivityFragment mainActivityFragment;
    
        @Override
        protected void setUp() throws Exception {
            TestUtils.enableMockitoOnDevicesAndEmulators();
            mainActivity = getActivity();
            mainActivityFragment = new MainActivityFragment();
        }
    
        public void testMainActivity() {
            Assert.assertNotNull(mainActivity);
        }
    
        public void testCowsCounter() {
            startFragment(mainActivityFragment);
            assertThat(mainActivityFragment.calculateYoungCows(10)).isEqualTo(2);
            assertThat(mainActivityFragment.calculateYoungCows(99)).isEqualTo(3);
        }
    
        private void startFragment( Fragment fragment ) {
            FragmentManager fragmentManager = mainActivity.getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.add(fragment, null);
            fragmentTransaction.commit();
    
            getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    getActivity().getSupportFragmentManager().executePendingTransactions();
                }
            });
    
            getInstrumentation().waitForIdleSync();
        }
    
    }
    

    如您所见,Test 类是 ActivityInstrumentationTestCase2 类的扩展。 此外,注意 startFragment 方法非常重要,该方法与 JUnit 示例相比发生了变化:默认情况下,测试不在 UI 线程上运行,我们需要显式调用执行挂起的 FragmentManager 的事务。

    - 如果你有 Dagger

    这里的情况越来越严重了:-)

    首先,我们正在摆脱 ActivityInstrumentationTestCase2 以支持 ActivityUnitTestCase 类,作为所有片段测试类的基类。

    像往常一样,这并不是那么简单,而且有几个陷阱(this 就是其中一个例子)。所以我们需要将我们的 AcitivityUnitTestCase 拉到 ActivityUnitTestCaseOverride

    在这里完整发布有点太长了,所以我将它的完整版上传到github;

    public abstract class ActivityUnitTestCaseOverride<T extends Activity>
            extends ActivityUnitTestCase<T> {
    
        ........
        private Class<T> mActivityClass;
    
        private Context mActivityContext;
        private Application mApplication;
        private MockParent mMockParent;
    
        private boolean mAttached = false;
        private boolean mCreated = false;
    
        public ActivityUnitTestCaseOverride(Class<T> activityClass) {
            super(activityClass);
            mActivityClass = activityClass;
        }
    
        @Override
        public T getActivity() {
            return (T) super.getActivity();
        }
    
        @Override
        protected void setUp() throws Exception {
            super.setUp();
    
            // default value for target context, as a default
            mActivityContext = getInstrumentation().getTargetContext();
        }
    
        /**
         * Start the activity under test, in the same way as if it was started by
         * {@link android.content.Context#startActivity Context.startActivity()}, providing the
         * arguments it supplied.  When you use this method to start the activity, it will automatically
         * be stopped by {@link #tearDown}.
         * <p/>
         * <p>This method will call onCreate(), but if you wish to further exercise Activity life
         * cycle methods, you must call them yourself from your test case.
         * <p/>
         * <p><i>Do not call from your setUp() method.  You must call this method from each of your
         * test methods.</i>
         *
         * @param intent                       The Intent as if supplied to {@link android.content.Context#startActivity}.
         * @param savedInstanceState           The instance state, if you are simulating this part of the life
         *                                     cycle.  Typically null.
         * @param lastNonConfigurationInstance This Object will be available to the
         *                                     Activity if it calls {@link android.app.Activity#getLastNonConfigurationInstance()}.
         *                                     Typically null.
         * @return Returns the Activity that was created
         */
        protected T startActivity(Intent intent, Bundle savedInstanceState,
                                  Object lastNonConfigurationInstance) {
            assertFalse("Activity already created", mCreated);
    
            if (!mAttached) {
                assertNotNull(mActivityClass);
                setActivity(null);
                T newActivity = null;
                try {
                    IBinder token = null;
                    if (mApplication == null) {
                        setApplication(new MockApplication());
                    }
                    ComponentName cn = new ComponentName(getInstrumentation().getTargetContext(), mActivityClass.getName());
                    intent.setComponent(cn);
                    ActivityInfo info = new ActivityInfo();
                    CharSequence title = mActivityClass.getName();
                    mMockParent = new MockParent();
                    String id = null;
    
                    newActivity = (T) getInstrumentation().newActivity(mActivityClass, mActivityContext,
                            token, mApplication, intent, info, title, mMockParent, id,
                            lastNonConfigurationInstance);
                } catch (Exception e) {
                    assertNotNull(newActivity);
                }
    
                assertNotNull(newActivity);
                setActivity(newActivity);
    
                mAttached = true;
            }
    
            T result = getActivity();
            if (result != null) {
                getInstrumentation().callActivityOnCreate(getActivity(), savedInstanceState);
                mCreated = true;
            }
            return result;
        }
    
        protected Class<T> getActivityClass() {
            return mActivityClass;
        }
    
        @Override
        protected void tearDown() throws Exception {
    
            setActivity(null);
    
            // Scrub out members - protects against memory leaks in the case where someone
            // creates a non-static inner class (thus referencing the test case) and gives it to
            // someone else to hold onto
            scrubClass(ActivityInstrumentationTestCase.class);
    
            super.tearDown();
        }
    
        /**
         * Set the application for use during the test.  You must call this function before calling
         * {@link #startActivity}.  If your test does not call this method,
         *
         * @param application The Application object that will be injected into the Activity under test.
         */
        public void setApplication(Application application) {
            mApplication = application;
        }
        .......
    }
    

    为所有片段测试创建一个抽象 AbstractFragmentTest:

    import android.app.Activity;
    import android.content.Intent;
    import android.content.pm.ActivityInfo;
    import android.content.res.Configuration;
    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    
    /**
     * Common base class for {@link Fragment} tests.
     */
    public abstract class AbstractFragmentTest<TFragment extends Fragment, TActivity extends FragmentActivity> extends ActivityUnitTestCaseOverride<TActivity> {
    
        private TFragment fragment;
        protected MockInjectionRegistration mocks;
    
        protected AbstractFragmentTest(TFragment fragment, Class<TActivity> activityType) {
            super(activityType);
            this.fragment = parameterIsNotNull(fragment);
        }
    
        @Override
        protected void setActivity(Activity testActivity) {
            if (testActivity != null) {
                testActivity.setTheme(R.style.AppCompatTheme);
            }
    
            super.setActivity(testActivity);
        }
    
        /**
         * Get the {@link Fragment} under test.
         */
        protected TFragment getFragment() {
            return fragment;
        }
    
        protected void setUpActivityAndFragment() {
            createMockApplication();
    
            final Intent intent = new Intent(getInstrumentation().getTargetContext(),
                    getActivityClass());
            startActivity(intent, null, null);
            startFragment(getFragment());
    
            getInstrumentation().callActivityOnStart(getActivity());
            getInstrumentation().callActivityOnResume(getActivity());
        }
    
        private void createMockApplication() {
            TestUtils.enableMockitoOnDevicesAndEmulators();
    
            mocks = new MockInjectionRegistration();
            TestApplication testApplication = new TestApplication(getInstrumentation().getTargetContext());
            testApplication.setModules(mocks);
            testApplication.onCreate();
            setApplication(testApplication);
        }
    
        private void startFragment(Fragment fragment) {
            FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.add(fragment, null);
            fragmentTransaction.commit();
        }
    }
    

    这里有几件重要的事情。

    1) 我们重写 setActivity() 方法来为活动设置 AppCompact 主题。没有它,测试服就会崩溃。

    2) setUpActivityAndFragment() 方法:

    I. 创建活动(=> getActivity() 开始返回非空值,在测试和正在测试的应用程序中) 1) onCreate() 调用的活动;

    2) onStart() 调用的活动;

    3) onResume() 调用的活动;

    II. 将片段附加并启动到活动

    1) onAttach() 被调用的片段;

    2) onCreateView() 被调用的片段;

    3) onStart() 被调用的片段;

    4) onResume() 被调用的片段;

    3) createMockApplication() 方法: 与非 Dagger 版本一样,在预步骤 1 中,我们在设备和模拟器上启用模拟。

    然后我们用我们的自定义 TestApplication 替换普通应用程序的注入!

    MockInjectionRegistration 看起来像:

    ....
    import javax.inject.Singleton;
    
    import dagger.Module;
    import dagger.Provides;
    import de.greenrobot.event.EventBus;
    
    import static org.mockito.Mockito.mock;
    import static org.mockito.Mockito.when;
    
    @Module(
            injects = {
    
                    ....
                    MainActivity.class,
                    MyWorkFragment.class,
                    HomeFragment.class,
                    ProfileFragment.class,
                    ....
            },
            addsTo = DelveMobileInjectionRegistration.class,
            overrides = true
    )
    public final class MockInjectionRegistration {
    
        .....
        public DataSource dataSource;
        public EventBus eventBus;
        public MixpanelAPI mixpanel;
        .....
    
        public MockInjectionRegistration() {
            .....
            dataSource = mock(DataSource.class);
            eventBus = mock(EventBus.class);
            mixpanel = mock(MixpanelAPI.class);
            MixpanelAPI.People mixpanelPeople = mock(MixpanelAPI.People.class);
            when(mixpanel.getPeople()).thenReturn(mixpanelPeople);
            .....
        }
    ...........
        @Provides
        @Singleton
        @SuppressWarnings("unused")
            // invoked by Dagger
        DataSource provideDataSource() {
            Guard.valueIsNotNull(dataSource);
            return dataSource;
        }
    
        @Provides
        @Singleton
        @SuppressWarnings("unused")
            // invoked by Dagger
        EventBus provideEventBus() {
            Guard.valueIsNotNull(eventBus);
            return eventBus;
        }
    
        @Provides
        @Singleton
        @SuppressWarnings("unused")
            // invoked by Dagger
        MixpanelAPI provideMixpanelAPI() {
            Guard.valueIsNotNull(mixpanel);
            return mixpanel;
        }
    .........
    }
    

    即我们向片段提供了它们的模拟版本,而不是真正的类。 (易于追踪,允许配置方法调用的结果等)。

    TestApplication只是你自定义的Application扩展,应该支持设置模块和初始化ObjectGraph。

    这些是开始编写测试的准备步骤 :) 现在是简单的部分,真正的测试:

    public class SearchFragmentTest extends AbstractFragmentTest<SearchFragment, MainActivity> {
    
        public SearchFragmentTest() {
            super(new SearchFragment(), MainActivity.class);
        }
    
        @UiThreadTest
        public void testOnCreateView() throws Exception {
            setUpActivityAndFragment();
    
            SearchFragment searchFragment = getFragment();
            assertNotNull(searchFragment.adapter);
            assertNotNull(SearchFragment.getSearchAdapter());
            assertNotNull(SearchFragment.getSearchSignalLogger());
        }
    
        @UiThreadTest
        public void testOnPause() throws Exception {
            setUpActivityAndFragment();
    
            SearchFragment searchFragment = getFragment();
            assertTrue(Strings.isNullOrEmpty(SharedPreferencesTools.getString(getActivity(), SearchFragment.SEARCH_STATE_BUNDLE_ARGUMENT)));
    
            searchFragment.searchBoxRef.setCurrentConstraint("abs");
            searchFragment.onPause();
    
            assertEquals(searchFragment.searchBoxRef.getCurrentConstraint(), SharedPreferencesTools.getString(getActivity(), SearchFragment.SEARCH_STATE_BUNDLE_ARGUMENT));
        }
    
        @UiThreadTest
        public void testOnQueryTextChange() throws Exception {
            setUpActivityAndFragment();
            reset(mocks.eventBus);
    
            getFragment().onQueryTextChange("Donald");
            Thread.sleep(300);
    
            // Should be one cached, one uncached event
            verify(mocks.eventBus, times(2)).post(isA(SearchRequest.class));
            verify(mocks.eventBus).post(isA(SearchLoadingIndicatorEvent.class));
        }
    
        @UiThreadTest
        public void testOnQueryUpdateEventWithDifferentConstraint() throws Exception {
            setUpActivityAndFragment();
    
            reset(mocks.eventBus);
    
            getFragment().onEventMainThread(new SearchResponse(new ArrayList<>(), "Donald", false));
    
            verifyNoMoreInteractions(mocks.eventBus);
        }
        ....
    }
    

    就是这样! 现在你已经为你的 Fragment 启用了 Instrumental/JUnit 测试。

    我真诚地希望这篇文章对某人有所帮助。

    【讨论】:

    • 这真是一件好事。感谢您与我们分享!
    • 更简单的方法是将calculateYoungCows() 方法提取到一个单独的类中并简单地对其进行单元测试。
    【解决方案2】:

    假设您有一个名为“MyFragmentActivity”的 FragmentActivity 类,其中使用 FragmentTransaction 添加了一个名为“MyFragment”的公共 Fragment 类。只需在您的测试项目中创建一个扩展 ActivityInstrumentationTestCase2 的“JUnit 测试用例”类。然后只需调用 getActivity() 并访问 MyFragment 对象及其公共成员即可编写测试用例。

    参考下面的代码sn-p:

    // TARGET CLASS
    public class MyFragmentActivity extends FragmentActivity {
        public MyFragment myFragment;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
            myFragment = new MyFragment();
            fragmentTransaction.add(R.id.mainFragmentContainer, myFragment);
            fragmentTransaction.commit();
        }
    }
    
    // TEST CLASS
    public class MyFragmentActivityTest extends android.test.ActivityInstrumentationTestCase2<MyFragmentActivity> {
        MyFragmentActivity myFragmentActivity;
        MyFragment myFragment;
    
        public MyFragmentActivityTest() {
            super(MyFragmentActivity.class);
        }
    
        @Override
        protected void setUp() throws Exception {
            super.setUp();
            myFragmentActivity = (MyFragmentActivity) getActivity();
            myFragment = myFragmentActivity.myFragment;
        }
    
        public void testPreConditions() {
            assertNotNull(myFragmentActivity);
            assertNotNull(myFragment);
        }
    
        public void testAnythingFromMyFragment() {
            // access any public members of myFragment to test
        }
    }
    

    我希望这会有所帮助。如果您觉得这很有用,请接受我的回答。谢谢。

    【讨论】:

    • 您如何解决 TestRunner(16162): java.lang.RuntimeException: Unable to resolve activity for: Intent { act=android.intent.action.MAIN flg=0x10000000 cmp=com.example /.test.MyFragmentActivityTest $MyFragmentActivity }
    • @mach 你能提供完整的堆栈跟踪吗?
    • 上面的例子不是单元测试,而是仪器测试。
    【解决方案3】:

    我很确定您可以按照您说的做,创建一个模拟 Activity 并从那里测试片段。 您只需在主项目中导出兼容性库,您就可以访问测试项目中的片段。 我将创建一个示例项目并在此处测试代码,并将根据我的发现更新我的答案。

    有关如何导出兼容性库的更多详细信息,请查看here

    【讨论】:

    • 你能在这里分享一些代码如何对片段进行单元测试。我在单元测试片段时遇到了麻烦!
    【解决方案4】:

    添加到@abhijit.mitkar 的答案。

    假设您的片段不是被测活动中的公共成员。

    protected void setUp() {
       mActivity = getActivity();
       mFragment = new TheTargetFragment();
    
       FragmentTransaction transaction = mActivity.getSupportFragmentManager().beginTransaction();
       transaction.add(R.id.fragment_container, mFragment, "FRAGMENT_TAG");
       transaction.commit();
    }
    

    上面代码的目的是用我们可以访问的新片段对象替换片段。

    下面的代码将允许您访问 Fragments UI 成员。

    TextView randomTextView= (TextView) mFragment.getView().findViewById(R.id.textViewRandom);
    

    从活动中获取用户界面不会为您提供预期的结果。

    TextView randomTextView= (TextView) mActivity.findViewById(R.id.textViewRandom);
    

    最后,如果您希望对 UI 进行一些更改。就像一个优秀的 android 开发者在主线程中做的那样。

    mActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            // set text view's value
        }
    });
    

    注意: 您可能希望在每次测试结束时给它一个 Thread.sleep() 。为避免锁定,getInstrumentation().waitForIdleSync();似乎并不总是有效。

    我使用 ActivityInstrumentationTestCase2,因为我在进行功能测试。

    【讨论】:

    • Cristopher mFragment.getView() 返回 null 我正在扩展 ActivityUnitTestCase 进行单元测试!
    • 您好,我正在使用 ActivityInstrumentationTestCase2,因为我正在做功能测试。抱歉,我没有尝试使用 ActivityUnitTestCase。应该提到这一点。
    • 谢谢克里斯托弗。我找到了解决方案。
    猜你喜欢
    • 2014-03-02
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 2014-11-25
    • 1970-01-01
    • 2018-06-14
    • 2021-01-03
    • 2019-01-29
    相关资源
    最近更新 更多