Как выполнить юнит-тест AsyncTask в Android
Рассмотрим код ниже. Как я могу проверить это без использования сторонних библиотек? Строка Assert никогда не выполняется, потому что это другой поток, и vm перестает работать. Большое спасибо!
public class FileParserTask extends AsyncTask<File, Void, ArrayList<City>> {
private FileParserResult mResult;
public interface FileParserResult {
void onFinish(ArrayList<City> cities);
}
public FileParserTask(final FileParserResult result) {
mResult = result;
}
@Override
protected ArrayList<City> doInBackground(File... files) {
ArrayList<City> cities = new ArrayList<>();
try {
InputStream is = new FileInputStream(files[0]);
JsonReader reader = new JsonReader(new InputStreamReader(is, "UTF-8"));
reader.beginArray();
while (reader.hasNext()) {
City city = new Gson().fromJson(reader, City.class);
cities.add(city);
}
reader.endArray();
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
Collections.sort(cities, (o1, o2) -> o1.getName().compareTo(o2.getName()));
mResult.onFinish(cities);
return cities;
}
}
Тестовый код:
@RunWith(AndroidJUnit4.class)
public class CityServiceTest {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "cities-medium.json");
@Test
public void givenInputAbuThenIShouldGetXResults() throws InterruptedException {
new FileParserTask(cities -> {
Assert.assertEquals("Input should give back 200 results", 3, cities.size());
}).execute(file);
}
}
3 ответа
Хотя код нужно тестировать:
Assert.assertEquals("Input should give back 200 results", 3, cities.size());
работает в AsyncTask
Это не очень важно для модульного тестирования. AsyncTask
Скорее всего, был тщательно протестирован Google, так что вы знаете, что он будет работать как AsyncTask
, Кажется, что реальное тестирование - это функциональность, которая должна выполняться в фоновом режиме, то есть бизнес-логика, содержащаяся в doInBackground
,
Думая об этом с точки зрения бизнес-логики, необходимо заполнить ArrayList<City>
и распространять его в приложение. Android предпочитает, чтобы это делалось в фоновом потоке, а распространение можно обрабатывать с помощью уведомлений и т. Д., Оба из которых были протестированы и выпущены как работающие в Google, поэтому вам не нужно включать их в модульный тест. Как вы населяете ArrayList<City>
настоящий юнит тест
AsyncTask
было бы уместно для интеграционного теста, но вы, скорее всего, будете тестировать другой аспект приложения для этого, то есть то, что оно отображает, а не то, что оно получает из фонового потока.
Так что для модульного теста я бы рефакторинг кода в doInBackground
так что он может быть протестирован независимо от того, как Android хочет, чтобы он работал.
К сожалению, вы переопределили метод onPostExecute в AsyncTask. Вы сохраняете обработчик Result, но нигде не используете его.
@Override
protected void onPostExecute(Object result) {
mResult.processFinish(result);
}
Что касается утверждения, то оно мне кажется хорошим.
Как вы говорите, проблема в том, что AsyncTask работает в фоновом потоке, через ExecutorService
, Как с Future
хотя, это обеспечивает get()
метод, который будет ожидать и возвращать результат.
new FileParserTask(cities -> {
Assert.assertEquals("Input should give back 200 results", 3, cities.size());
}).execute(file).get();