【问题标题】:How to unit test AsyncTask in android如何在android中对AsyncTask进行单元测试
【发布时间】:2018-03-14 11:12:55
【问题描述】:

考虑下面的代码。如何在不使用第三方库的情况下进行测试? 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);
    }
}

【问题讨论】:

标签: junit android-asynctask android-junit


【解决方案1】:

虽然你需要测试的代码:

Assert.assertEquals("Input should give back 200 results", 3, cities.size());

正在AsyncTask 中运行,这与单元测试并不真正相关。 AsyncTask 很可能已经过 Google 的广泛测试,因此您知道它可以用作 AsyncTask。真正的测试似乎是需要在后台运行的功能,即doInBackground中包含的业务逻辑。

从业务逻辑的角度考虑,需要填充 ArrayList&lt;City&gt; 并将其传播到应用程序。 Android 更喜欢在后台线程上完成此操作,并且可以通过通知等处理传播,这两者都已经过测试并由 Google 发布,因此您实际上不需要将它们包含在单元测试中。你如何填充ArrayList&lt;City&gt; 才是真正的单元测试。

AsyncTask 与集成测试相关,但您很可能会为此测试应用程序的不同方面,即它显示的内容而不是从后台线程接收的内容。

因此,对于单元测试,我将重构 doInBackground 中的代码,以便可以独立于 Android 希望它运行的方式对其进行测试。

【讨论】:

    【解决方案2】:

    抱歉,您是否重写了 AsyncTask 的 onPostExecute 方法。 您保留了 Result 处理程序,但没有在任何地方使用它。

    @Override
    protected void onPostExecute(Object result) {
        mResult.processFinish(result);
    }
    

    至于断言,它对我来说看起来不错。

    【讨论】:

    • 抱歉忘记了方法规范中的类型 onPostExecute(ArrayList result)
    【解决方案3】:

    正如你所说,问题是 AsyncTask 在后台线程中运行,通过ExecutorService。不过,与 Future 一样,它提供了一个 get() 方法,该方法将等待并返回结果。

    new FileParserTask(cities -> {
        Assert.assertEquals("Input should give back 200 results", 3, cities.size());
    }).execute(file).get();
    

    【讨论】:

    • 不,这不起作用。测试运行失败:由于“进程崩溃”,检测运行失败。
    猜你喜欢
    • 1970-01-01
    • 2016-12-16
    • 1970-01-01
    • 2020-09-25
    • 2022-11-17
    • 2016-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多