我有一个非常简单的AsyncTask实现示例,在使用Android JUnit框架测试它时遇到了问题。
当我在普通应用程序中示例化和执行它时,它运行得很好。但是,当从任何Android测试框架类(如***AndroidTestCase***、ActivityUnitTestCase、***ActivityInstrumentationTestCase 2***等)执行它时,它会表现得很奇怪:
- 正确执行
doInBackground()
方法 - 然而,它并不调用任何通知方法(
onPostExecute()
、onProgressUpdate()
等)--只是默默地忽略它们,而不显示任何错误。
这是一个非常简单的AsyncTask示例:
package kroz.andcookbook.threads.asynctask;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ProgressBar;
import android.widget.Toast;
public class AsyncTaskDemo extends AsyncTask<Integer, Integer, String> {
AsyncTaskDemoActivity _parentActivity;
int _counter;
int _maxCount;
public AsyncTaskDemo(AsyncTaskDemoActivity asyncTaskDemoActivity) {
_parentActivity = asyncTaskDemoActivity;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
_parentActivity._progressBar.setVisibility(ProgressBar.VISIBLE);
_parentActivity._progressBar.invalidate();
}
@Override
protected String doInBackground(Integer... params) {
_maxCount = params[0];
for (_counter = 0; _counter <= _maxCount; _counter++) {
try {
Thread.sleep(1000);
publishProgress(_counter);
} catch (InterruptedException e) {
// Ignore
}
}
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int progress = values[0];
String progressStr = "Counting " + progress + " out of " + _maxCount;
_parentActivity._textView.setText(progressStr);
_parentActivity._textView.invalidate();
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
_parentActivity._progressBar.setVisibility(ProgressBar.INVISIBLE);
_parentActivity._progressBar.invalidate();
}
@Override
protected void onCancelled() {
super.onCancelled();
_parentActivity._textView.setText("Request to cancel AsyncTask");
}
}
这是一个测试用例。这里的 AsyncTaskDemoActivity 是一个非常简单的Activity,它提供了用于在模式下测试AsyncTask的UI:
package kroz.andcookbook.test.threads.asynctask;
import java.util.concurrent.ExecutionException;
import kroz.andcookbook.R;
import kroz.andcookbook.threads.asynctask.AsyncTaskDemo;
import kroz.andcookbook.threads.asynctask.AsyncTaskDemoActivity;
import android.content.Intent;
import android.test.ActivityUnitTestCase;
import android.widget.Button;
public class AsyncTaskDemoTest2 extends ActivityUnitTestCase<AsyncTaskDemoActivity> {
AsyncTaskDemo _atask;
private Intent _startIntent;
public AsyncTaskDemoTest2() {
super(AsyncTaskDemoActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
_startIntent = new Intent(Intent.ACTION_MAIN);
}
protected void tearDown() throws Exception {
super.tearDown();
}
public final void testExecute() {
startActivity(_startIntent, null, null);
Button btnStart = (Button) getActivity().findViewById(R.id.Button01);
btnStart.performClick();
assertNotNull(getActivity());
}
}
所有这些代码都运行得很好,除了AsyncTask在Android测试框架中执行时不会调用其通知方法。
9条答案
按热度按时间8aqjt8rx1#
我在实现一些单元测试时遇到了类似的问题。我必须测试一些与Executors一起工作的服务,并且我需要让我的服务回调与来自ApplicationTestCase类的测试方法同步。通常测试方法本身在回调被访问之前就完成了,所以通过回调发送的数据不会被测试。尝试应用@UiThreadTest bust仍然没有工作。
我发现了下面的方法,它很有效,我现在仍然使用它。我只是使用CountDownLatch信号对象来实现wait-notify(您可以使用synchronized(lock){... lock.notify();},但这会导致代码很难看)机制。
xvw2m8pv2#
我找到了很多相似的答案,但没有一个能正确地将所有部分组合在一起。因此,在JUnit测试用例中使用android.os.AsyncTask时,这是一个正确的实现。
nkcskrwz3#
解决这个问题的方法是在
runTestOnUiThread()
中运行任何调用AsyncTask的代码:默认情况下,junit在一个独立的线程中运行测试,而不是在主应用程序UI中运行。这是因为AsyncTask依赖于主线程的
Looper
和MessageQueue
来使其内部处理程序正常工作。注:
我以前建议在测试方法上使用
@UiThreadTest
作为装饰器,以强制测试在主线程上运行,但这对于测试AsyncTask并不完全正确,因为当您的测试方法在主线程上运行时,主MessageQueue上不会处理任何消息-包括AsyncTask发送的有关其进度的消息,这会导致您的测试挂起。piwo6bdm4#
如果您不介意在调用线程中执行AsyncTask(在单元测试中应该没问题),您可以在当前线程中使用Executor,如https://stackoverflow.com/a/6583868/1266123中所述
然后在单元测试中像这样运行AsyncTask
这仅适用于HoneyComb和更高版本。
nhjlsmyf5#
我为Android编写了足够多的unitests,只是想分享如何做到这一点。
首先,这里是助手班,负责等待和放行服务员。没什么特别的:
同步通话器
接下来,让我们用一个方法创建接口,当工作完成时,应该从
AsyncTask
调用该方法。当然,我们也想测试我们的结果:测试责任它
接下来,让我们创建一些我们要测试的Task的框架:
最后--我们最统一的班级:
测试生成组任务
就这样了。
希望能对某人有所帮助。
icomxhvb6#
如果您要测试
doInBackground
方法的结果,可以使用此方法。覆写onPostExecute
方法并在该处执行测试。若要等候AsyncTask完成,请使用CountDownLatch。latch.await()
会一直等候,直到倒数从1(初始化时设定)到0(由countdown()
方法完成)为止。kq4fsx7k7#
使用
join
怎么样?zysjyyx48#
使用此简单解决方案
ffdz8vbo9#
大多数解决方案都需要为每个测试编写大量代码,或者需要更改类结构。如果您有许多测试情况或项目中有许多AsyncTasks,我发现这很难使用。
有一个library可以简化
AsyncTask
的测试过程。基本上,它运行AsyncTask并测试在调用
postComplete()
后返回的结果。