【问题标题】:Simple Espresso test "Looped for x iterations over 60sec" error简单的 Espresso 测试“循环进行 x 次迭代超过 60 秒”错误
【发布时间】:2016-08-24 20:35:08
【问题描述】:

我实际上尝试使用 Espresso 设置一些单元测试,经过几个小时的研究后,该应用程序只执行点击并通过 EditText 获得焦点,但之后就什么都没有了

Caused by: android.support.test.espresso.AppNotIdleException: Looped for 1996 iterations over 60 SECONDS. The following Idle Conditions failed .

我已删除所有动画和 SwipeRefreshLayout,因为我发现 swiperefresh 存在错误

我实际上使用了一些回调来替换 Activity 中的当前片段

如果有人有一些提示,我会在搜索 4 小时后退出 u_u

谢谢你:)


我的 Gradle 依赖项:

// App dependencies
compile 'com.android.support:support-annotations:23.3.0'
compile 'com.google.guava:guava:18.0'
// Testing-only dependencies
// Force usage of support annotations in the test app, since it is internally used by the runner module.
androidTestCompile 'com.android.support:support-annotations:23.3.0'
androidTestCompile 'com.android.support.test:runner:0.4.1'
androidTestCompile 'com.android.support.test:rules:0.4.1'
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'

我已经在 defaultConfig 中添加了这个:

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

这是我的测试:

@RunWith(AndroidJUnit4.class)
@LargeTest
public class HelloWorldEspressoTest {

    public static final String USERNAME = "do_f";

    @Rule
    public ActivityTestRule<LoginActivity> mActivityRule = new ActivityTestRule(LoginActivity.class);

    private LoginActivity mActivity = null;

    @Before
    public void setActivity() {
        mActivity = mActivityRule.getActivity();
    }

    @Test
    public void login_LoginActivity() {

        onView(withId(R.id.menu_login)).perform(click());

        onView(withId(R.id.login_username))
                .perform(typeText(USERNAME), closeSoftKeyboard());
    }
}

有我的活动:

public class LoginActivity extends AppCompatActivity
        implements MenuFragment.OnFragmentInteractionListener {

    private FragmentManager fm;

    public static void newActivity(Activity activity)
    {
        Intent i = new Intent(activity, LoginActivity.class);
        activity.startActivity(i);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        SharedPreferences sp = getSharedPreferences(Utils.SP, Context.MODE_PRIVATE);

        if (!sp.getString(Utils.TOKEN, "null").equals("null"))
        {
            MainActivity.newActivity(this);
            finish();
        }

        fm = getFragmentManager();
        fm.beginTransaction()
                .replace(R.id.container, MenuFragment.newInstance())
                .addToBackStack(null)
                .commit();
    }

    @Override
    public void onBackPressed()
    {
        if (getFragmentManager().getBackStackEntryCount() > 1)
            getFragmentManager().popBackStack();
        else
            super.onBackPressed();
    }

    @Override
    public void showLogin() {
        fm.beginTransaction()
                .replace(R.id.container, LoginFragment.newInstance())
                .addToBackStack(null)
                .commit();
    }

    @Override
    public void showRegister() {
        fm.beginTransaction()
                .replace(R.id.container, RegisterFragment.newInstance())
                .addToBackStack(null)
                .commit();
    }
}

还有我的登录片段:

    private static final String        TAG = "LoginFragment";

@Bind(R.id.loading_spinner)
ProgressBar loading;

@Bind(R.id.content)
LinearLayout content;

@Bind(R.id.login_username)
EditText        username;

@Bind(R.id.login_password)
EditText        password;

public LoginFragment() {

}

public static LoginFragment newInstance() {
    return new LoginFragment();
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.login_fragment_login, container, false);
    ButterKnife.bind(this, v);
    return v;
}

@Override
public void onActivityCreated(Bundle saveInstanceState) {
    super.onActivityCreated(saveInstanceState);
}

@OnClick(R.id.login_submit)
public void onSubmit(View v)
{
    if (username.getText().length() == 0
            || password.getText().length() == 0)
    {
        Snackbar.make(getView(), "blabla", Snackbar.LENGTH_SHORT).show();
        return ;
    }
    //hideContent();
    LoginPost p = new LoginPost(username.getText().toString(), password.getText().toString());
    Call<LoginResponse> call = RestClient.get().login(p);
    call.enqueue(new Callback<LoginResponse>() {
        @Override
        public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
            if (response.body() == null) {
                String msg = getResources().getString(R.string.login_error_bad_credentials);
                Snackbar.make(getView(), msg, Snackbar.LENGTH_SHORT).show();
                //showContent();
            } else {
                SharedPreferences sp = getActivity().getSharedPreferences(Utils.SP, Context.MODE_PRIVATE);
                sp.edit().putString(Utils.TOKEN, response.body().getToken()).apply();
                sp.edit().putString(Utils.USERNAME, username.getText().toString()).apply();
                MainActivity.newActivity(getActivity());
                getActivity().finish();
            }
        }

        @Override
        public void onFailure(Call<LoginResponse> call, Throwable t) {
            Snackbar.make(getView(), "onFailure", Snackbar.LENGTH_SHORT).show();
            //showContent();
        }
    });
}

【问题讨论】:

  • 检查这个post,在gradle中使用animationsDisabled。

标签: android unit-testing android-espresso


【解决方案1】:

Espresso 旨在等到您的应用程序中没有待处理的 UI 动画或 AsyncTask 后再继续测试。来自the docs,强调我的:

Espresso 提供了一套复杂的同步功能。然而,框架的这一特性仅适用于在 MessageQueue 上发布消息的操作,例如在屏幕上绘制其内容的 View 的子类。

android.support.test.espresso.AppNotIdleException 最可能的原因是 Espresso 正在等待完成的 UI 动画或 AsyncTask 正在进行。

例如,如果您的布局中有一个 ProgressBar 元素,则需要设置可见性 loading.setVisibility(View.GONE);,因为 Espresso 将该元素解释为正在进行的 UI 动画,并且将等待它消失以继续测试。

【讨论】:

  • @ivan.panasiuk 您的 TimeOutTimer 是否控制 UI 上的任何内容? TimeOutTimer 是否扩展了另一个类?在 Android 文档中看不到它
【解决方案2】:

我找到了解决方案,循环迭代是由这个引起的

<ProgressBar
    android:id="@+id/loading_spinner"
    android:layout_width="150dp"
    android:layout_height="150dp"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true"
    android:indeterminateTintMode="src_atop"
    android:indeterminateTint="@color/ganjify"
    android:alpha="0"
    android:layout_gravity="center" />

因为我没有在不使用时将可见性设置为 GONE!

loading.setVisibility(View.GONE);

【讨论】:

  • 我也有同样的问题,我在进度条加载时将可见性设置为 GONE 以检查它,但仍然遇到同样的问题...
  • @DineshVG 嘿,你应该检查你所有的动画是否完成,否则espresso测试会循环
  • 对我来说也是一样,将 alpha 0 而不是可见性设置为消失 -> AppNotIdleException(当你知道它时很明显:D)
  • @crysxd 是的,当你知道它在哪里时,你会说 omagad 很明显:D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-30
  • 2020-11-04
  • 1970-01-01
  • 2010-11-28
  • 2015-12-05
  • 1970-01-01
相关资源
最近更新 更多