3

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

3 回答 3

4

虽然您需要测试的代码:

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 希望它运行的方式对其进行测试。

于 2018-03-28T08:11:02.107 回答
1

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

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

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

于 2018-03-28T09:00:38.150 回答
0

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

new FileParserTask(cities -> {
    Assert.assertEquals("Input should give back 200 results", 3, cities.size());
}).execute(file).get();
于 2018-03-22T21:10:27.223 回答