我试图用Espresso来测试我的UI.当我登录到我的应用程序时,我打电话给Parse API(网络呼叫)来验证用户名和密码.如果一切都很好,用户将被引导到一个新的活动.我想测试这个,但我似乎无法使用闲置的资源.
码:
public class ApplicationTest extends ActivityInstrumentationTestCase2<LoginActivity> { private CountingIdlingResource fooServerIdlingResource; public ApplicationTest() { super(LoginActivity.class); } @Before public void setUp() throws Exception { super.setUp(); injectInstrumentation(InstrumentationRegistry.getInstrumentation()); getActivity(); CountingIdlingResource countingResource = new CountingIdlingResource("FooServerCalls"); this.fooServerIdlingResource = countingResource; Espresso.registerIdlingResources(countingResource); } public void testChangeText_sameActivity() { // Type text and then press the button. onView(withId(R.id.username)) .perform(typeText("s@s.nl"),closeSoftKeyboard()); onView(withId(R.id.password)) .perform(typeText("s"),closeSoftKeyboard()); if(performClick()) onView(withId(R.id.main_relative_layout)) .check(matches(isDisplayed())); // Check that the text was changed. } public boolean performClick(){ fooServerIdlingResource.increment(); try { onView(withId(R.id.login)).perform(click()); return true; } finally { fooServerIdlingResource.decrement(); } } @SuppressWarnings("javadoc") public final class CountingIdlingResource implements IdlingResource { private static final String TAG = "CountingIdlingResource"; private final String resourceName; private final AtomicInteger counter = new AtomicInteger(0); private final boolean debugCounting; // written from main thread,read from any thread. private volatile ResourceCallback resourceCallback; // read/written from any thread - used for debugging messages. private volatile long becameBusyAt = 0; private volatile long becameIdleAt = 0; /** * Creates a CountingIdlingResource without debug tracing. * * @param resourceName the resource name this resource should report to Espresso. */ public CountingIdlingResource(String resourceName) { this(resourceName,false); } /** * Creates a CountingIdlingResource. * * @param resourceName the resource name this resource should report to Espresso. * @param debugCounting if true increment & decrement calls will print trace information to logs. */ public CountingIdlingResource(String resourceName,boolean debugCounting) { this.resourceName = checkNotNull(resourceName); this.debugCounting = debugCounting; } @Override public String getName() { return resourceName; } @Override public boolean isIdleNow() { return counter.get() == 0; } @Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { this.resourceCallback = resourceCallback; } /** * Increments the count of in-flight transactions to the resource being monitored. * <p/> * This method can be called from any thread. */ public void increment() { int counterVal = counter.getAndIncrement(); if (0 == counterVal) { becameBusyAt = SystemClock.uptimeMillis(); } if (debugCounting) { Log.i(TAG,"Resource: " + resourceName + " in-use-count incremented to: " + (counterVal + 1)); } } /** * Decrements the count of in-flight transactions to the resource being monitored. * <p/> * If this operation results in the counter falling below 0 - an exception is raised. * * @throws IllegalStateException if the counter is below 0. */ public void decrement() { int counterVal = counter.decrementAndGet(); if (counterVal == 0) { // we've gone from non-zero to zero. That means we're idle now! Tell espresso. if (null != resourceCallback) { resourceCallback.onTransitionToIdle(); } becameIdleAt = SystemClock.uptimeMillis(); } if (debugCounting) { if (counterVal == 0) { Log.i(TAG,"Resource: " + resourceName + " went idle! (Time spent not idle: " + (becameIdleAt - becameBusyAt) + ")"); } else { Log.i(TAG,"Resource: " + resourceName + " in-use-count decremented to: " + counterVal); } } checkState(counterVal > -1,"Counter has been corrupted!"); } /** * Prints the current state of this resource to the logcat at info level. */ public void dumpStateToLogs() { StringBuilder message = new StringBuilder("Resource: ") .append(resourceName) .append(" inflight transaction count: ") .append(counter.get()); if (0 == becameBusyAt) { Log.i(TAG,message.append(" and has never been busy!").toString()); } else { message.append(" and was last busy at: ") .append(becameBusyAt); if (0 == becameIdleAt) { Log.w(TAG,message.append(" AND NEVER WENT IDLE!").toString()); } else { message.append(" and last went idle at: ") .append(becameIdleAt); Log.i(TAG,message.toString()); } } } }
}
我现在得到的例外如下:
ndroid.support.test.espresso.IdlingResourceTimeoutException: Wait for [FooServerCalls] to become idle timed out
当我运行测试,用户名和密码正在填写,但执行点击永远不会被调用,我几秒钟后得到异常.我该如何正确地实现空闲资源?
编辑 –
我建议使用Calabash for Android. Calabash类似,但不需要您更改您的应用程序代码进行测试.
解决方法
像其他答案所示,countingIdlingResource并不真正适用于您的用例.
我一直在做的是添加一个接口 – 让我们将这个ProgressListener称为具有待等待资源(异步后台工作,更长的联网会话等)的活动/片段的一个字段,以及每次通知它的方法进度显示或被驳回.
我假设你有你的凭据验证逻辑,并且在LoginActivity中调用Parse API,如果成功,它将调用MainActivity的意图.
public class LoginActivity extends AppCompatActivity { private ProgressListener mListener; ... public interface ProgressListener { public void onProgressShown(); public void onProgressDismissed(); } public void setProgressListener(ProgressListener progressListener) { mListener = progressListener; } ... public void onLoginButtonClicked (View view) { String username = mUsername.getText().toString(); String password = mPassword.getText().toString(); // validate credentials for blanks and so on // show progress and call parse login in background method showProgress(); ParseUser.logInInBackground(username,password,new LogInCallback() { @Override public void done(ParseUser parseUser,ParseException e) { dismissProgress(); if (e == null){ // Success!,continue to MainActivity via intent Intent intent = new Intent (LoginActivity.this,MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent); } else { // login Failed dialog or similar. } } }); } private void showProgress() { // show the progress and notify the listener ... notifyListener(mListener); } private void dismissProgress() { // hide the progress and notify the listener ... notifyListener(mListener); } public boolean isInProgress() { // return true if progress is visible } private void notifyListener(ProgressListener listener) { if (listener == null){ return; } if (isInProgress()){ listener.onProgressShown(); } else { listener.onProgressDismissed(); } } }
然后,简单地实现IdlingResource类,并在资源从忙到空到ResourceCallBack时重写其通信方式进行通信
public class ProgressIdlingResource implements IdlingResource { private ResourceCallback resourceCallback; private LoginActivity loginActivity; private LoginActivity.ProgressListener progressListener; public ProgressIdlingResource(LoginActivity activity){ loginActivity = activity; progressListener = new LoginActivity.ProgressListener() { @Override public void onProgressShown() { } @Override public void onProgressDismissed() { if (resourceCallback == null){ return ; } //Called when the resource goes from busy to idle. resourceCallback.onTransitionToIdle(); } }; loginActivity.setProgressListener (progressListener); } @Override public String getName() { return "My idling resource"; } @Override public boolean isIdleNow() { // the resource becomes idle when the progress has been dismissed return !loginActivity.isInProgress(); } @Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { this.resourceCallback = resourceCallback; } }
最后一步是在测试的setUp()方法中注册您的自定义空闲资源:
Espresso.registerIdlingResources(new ProgressIdlingResource((LoginActivity) getActivity()));
就是这样!现在espresso将等待您的登录过程完成,然后继续所有其他测试.
请让我知道,如果我不够清楚,或者这是你所需要的.