Android 如何使用Mockito进行异步任务模拟?
我试图改进我所做的一些单元测试,所以我使用mockito来模拟一些对象。所以现在我有两个问题:我是否应该尝试模拟AsyncTask,以及(如果是)如何使用这个模拟对象来调用模拟对象的Android 如何使用Mockito进行异步任务模拟?,android,junit,android-asynctask,mockito,Android,Junit,Android Asynctask,Mockito,我试图改进我所做的一些单元测试,所以我使用mockito来模拟一些对象。所以现在我有两个问题:我是否应该尝试模拟AsyncTask,以及(如果是)如何使用这个模拟对象来调用模拟对象的doInBackground()方法 我试过几种方法,但仍然不起作用。我的测试仍然给我一个断言失败: 异步任务的执行方式(在StudioActivity.java中): ..... LocationTask task = new LocationTask(); task.execute((LocationManag
doInBackground()
方法
我试过几种方法,但仍然不起作用。我的测试仍然给我一个断言失败:
异步任务的执行方式(在StudioActivity.java中):
.....
LocationTask task = new LocationTask();
task.execute((LocationManager) this.getSystemService(Context.LOCATION_SERVICE));
.....
public class LocationTask extends AsyncTask<LocationManager, Void, String> {
private LocationManager mLocationManager;
// private TextView mLocText;
@Override
protected void onPreExecute() {
super.onPreExecute();
// mLocText = (TextView) findViewById(R.id.textView_location);
// mLocText.setVisibility(View.VISIBLE);
}
@Override
public String doInBackground(LocationManager... params) {
mLocationManager = params[0];
Location loc = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Geocoder gcd = new Geocoder(getApplicationContext(), Locale.getDefault());
List<Address> addresses;
try {
addresses = gcd.getFromLocation(loc.getLatitude(), loc.getLongitude(), 1);
if (addresses.size() > 0) {
return (addresses.get(0).getLocality() + ", " + addresses.get(0).getCountryName());
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String result) {
mPreviewFragment.setLocation(result);
mLocation = result;
}
}
@UiThreadTest
public void testGeolocalistationLabel() throws InterruptedException, ExecutionException{
LocationTask mockLocationTask = mock(StudioActivity.LocationTask.class);
when(mockLocationTask.doInBackground((LocationManager[]) any())).thenReturn("JUnit, Location");
mStudioBoastPreviewFragment.getGeoloc().performClick();
assertEquals("JUnit, Location",mStudioBoastPreviewFragment.getGeolocTextView().getText());
verify(mockLocationTask).doInBackground((LocationManager[]) any());
}
junit.framework.AssertionFailedError: expected:<JUnit, Location> but was:<>
at com.c4mprod.bhost.test.TestStudioActivity.testGeolocalistationLabel(TestStudioActivity.java:255)
我的异步任务(在StudioActivity.java中):
.....
LocationTask task = new LocationTask();
task.execute((LocationManager) this.getSystemService(Context.LOCATION_SERVICE));
.....
public class LocationTask extends AsyncTask<LocationManager, Void, String> {
private LocationManager mLocationManager;
// private TextView mLocText;
@Override
protected void onPreExecute() {
super.onPreExecute();
// mLocText = (TextView) findViewById(R.id.textView_location);
// mLocText.setVisibility(View.VISIBLE);
}
@Override
public String doInBackground(LocationManager... params) {
mLocationManager = params[0];
Location loc = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Geocoder gcd = new Geocoder(getApplicationContext(), Locale.getDefault());
List<Address> addresses;
try {
addresses = gcd.getFromLocation(loc.getLatitude(), loc.getLongitude(), 1);
if (addresses.size() > 0) {
return (addresses.get(0).getLocality() + ", " + addresses.get(0).getCountryName());
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String result) {
mPreviewFragment.setLocation(result);
mLocation = result;
}
}
@UiThreadTest
public void testGeolocalistationLabel() throws InterruptedException, ExecutionException{
LocationTask mockLocationTask = mock(StudioActivity.LocationTask.class);
when(mockLocationTask.doInBackground((LocationManager[]) any())).thenReturn("JUnit, Location");
mStudioBoastPreviewFragment.getGeoloc().performClick();
assertEquals("JUnit, Location",mStudioBoastPreviewFragment.getGeolocTextView().getText());
verify(mockLocationTask).doInBackground((LocationManager[]) any());
}
junit.framework.AssertionFailedError: expected:<JUnit, Location> but was:<>
at com.c4mprod.bhost.test.TestStudioActivity.testGeolocalistationLabel(TestStudioActivity.java:255)
或
失败:
.....
LocationTask task = new LocationTask();
task.execute((LocationManager) this.getSystemService(Context.LOCATION_SERVICE));
.....
public class LocationTask extends AsyncTask<LocationManager, Void, String> {
private LocationManager mLocationManager;
// private TextView mLocText;
@Override
protected void onPreExecute() {
super.onPreExecute();
// mLocText = (TextView) findViewById(R.id.textView_location);
// mLocText.setVisibility(View.VISIBLE);
}
@Override
public String doInBackground(LocationManager... params) {
mLocationManager = params[0];
Location loc = mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Geocoder gcd = new Geocoder(getApplicationContext(), Locale.getDefault());
List<Address> addresses;
try {
addresses = gcd.getFromLocation(loc.getLatitude(), loc.getLongitude(), 1);
if (addresses.size() > 0) {
return (addresses.get(0).getLocality() + ", " + addresses.get(0).getCountryName());
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String result) {
mPreviewFragment.setLocation(result);
mLocation = result;
}
}
@UiThreadTest
public void testGeolocalistationLabel() throws InterruptedException, ExecutionException{
LocationTask mockLocationTask = mock(StudioActivity.LocationTask.class);
when(mockLocationTask.doInBackground((LocationManager[]) any())).thenReturn("JUnit, Location");
mStudioBoastPreviewFragment.getGeoloc().performClick();
assertEquals("JUnit, Location",mStudioBoastPreviewFragment.getGeolocTextView().getText());
verify(mockLocationTask).doInBackground((LocationManager[]) any());
}
junit.framework.AssertionFailedError: expected:<JUnit, Location> but was:<>
at com.c4mprod.bhost.test.TestStudioActivity.testGeolocalistationLabel(TestStudioActivity.java:255)
junit.framework.AssertionFailedError:应为:但为:
位于com.c4mprod.bhost.test.TestStudioActivity.TestGeoLocalizationLabel(TestStudioActivity.java:255)
没有嘲弄,这是有效的。但是测试的执行时间很长。这就是为什么我想使用Mockito:提高测试速度,避免连接问题或服务器错误。我只想测试该位置是否显示在mstudiobowPreviewFragment.getgeoloctView()
中
在这两种情况下,我都有一个断言失败,所以我想知道哪种方法是最好的,以及如何使用它来模拟这个doInBackground()
。或者如果有其他方法来模拟异步任务
谢谢你的帮助 不幸的是,我对安卓知之甚少,但我对Mockito知之甚少 我必须问的一个问题是: 您的StudioOwFragment如何实际获取LocationTask的实例?从您的测试代码中,我所能猜测的是您的模拟LocationTask没有被注入-MstudioBowPreviewFragment似乎是您的测试类的成员,而mockLocationTask是在方法范围内声明和实例化的,因此我无法想象MstudioBowPreviewFragment实际上是如何使用您的模拟的 然后是模拟的问题: 我看到LocationTask继承自AsyncTask。doInBackground(…)是如何被呼叫的?您是在调用它,还是由AsyncTask的内部逻辑调用它(类似于Thread.start()调用的Thread.run())?请记住,Mockito创建了一个没有逻辑的哑代理对象。因此,如果您依赖于AsyncTask调用doInBackground(…)的一些内部逻辑,那么这个内部逻辑将不存在于您的模拟中 换句话说,如果这是一个单元测试,那么您并不关心是否首先调用doInBackground(…),因为您的外部客户机代码不应该依赖于AsyncTask的内部或具体的子类LocationTask。回到线程示例:您模拟了Thread.start(),而不是Thread.run() 如果您真的想进行单元测试,那么应该分别测试这两个类,隔离其中任何一个类中的潜在错误。因此,如果操作正确,模拟LocationTask是一个好主意
另一方面,如果您想测试两个组件之间的交互,那么这实际上不再是一个单元测试,而是一个完全不同的故事。我不确定是否正确理解您的测试。你要考的是哪门课?“mstudiowFragment”还是LocationTask?我看不出你模拟的LocationTask是如何被注入“mstudioPreviewFragment”的。据我所知,您的模拟LocationTask根本没有被使用。@joerx mstudiobowPreviewFragment是一个包含我要测试的文本视图的片段。此片段是名为StudioActivity的活动的一部分,LocationTask是StudioActivity的内部类。当我在StudioBulf PreviewFragment中单击一个切换按钮时,这将启动AsyncTask LocationTask,它将地理定位用户并在我前面提到的文本视图中显示他的位置。为了回答您的问题:我正在测试的类是studiobowPreviewFragment。我的doInBackground()是这样调用的:-在我的测试用例中,我通过以下方式执行geoloc按钮:
solo.clickOnView(mstudiobowPreviewFragment.getGeoloc())代码>-在studiovableviewFragment中,my geoloc按钮有一个OnCheck侦听器:geoloc.setOnCheckedChangeListener(((StudioActivity)getActivity())代码>-此侦听器在StudioActivity中调用执行以下操作的方法:LocationTask task=new LocationTask();执行((LocationManager)…)代码>-如此类推,doInBackground()
被调用…然后您实际需要删除的是LocationTask.execute()-如:doReturn(…).when(LocationTask).execute(…)。调用doInBackground()的事实是LocationTask的一个实现细节,只要测试ViewFragment,您就不必担心。刚才看到代码中的另一个问题:在侦听器中,您似乎使用了“New LocationTask()”—如果您在测试的类中创建依赖项的新实例,您根本无法模拟该依赖关系,因为您无法实际告诉您的类使用模拟而不是实际对象。换句话说,耦合太紧。这是一个设计问题。您应该尝试找到一种方法来注入LocationTask或将任务的内部逻辑移到其他地方,例如某个服务并模拟该服务。