Как выполнить юнит-тест 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();
Другие вопросы по тегам