Reputation: 2660
Consider below code. How can I test this without using third party libraries? The Assert line is never executed, because it is a different thread and the vm stops running. Many thanks!
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;
}
}
Test code:
@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);
}
}
Upvotes: 3
Views: 3359
Reputation: 405
Sorry, did you override the onPostExecute method of the AsyncTask. You are keeping the Result handler, but not using it anywhere.
@Override
protected void onPostExecute(Object result) {
mResult.processFinish(result);
}
As for the assertion it looks good to me as it is.
Upvotes: 1
Reputation: 4630
Although the code you need to test:
Assert.assertEquals("Input should give back 200 results", 3, cities.size());
is being run in an AsyncTask
, that's not really relevant to unit testing. AsyncTask
has most likely been extensively tested by Google so you know that it will work as an AsyncTask
. The real testing seems to be the functionality that needs to be run in the background, i.e. the business logic contained in doInBackground
.
Thinking about it in terms of business logic, there is a need to populate an ArrayList<City>
and propagate it to the app. Android prefers this to be done on a background thread and propagation can be handled by notifications etc, both of which have been tested and released as working by Google so you don't really need to include them in a unit test. How you populate ArrayList<City>
is the real unit test.
AsyncTask
would be relevant for an integration test but you'd most likely be testing a different aspect of the app for that, i.e. what it displays rather than what it receives from a background thread.
So for a unit test I'd refactor out the code in doInBackground
so that it can be tested independently of how Android wants it to be run.
Upvotes: 4
Reputation: 10931
As you say, the problem is the AsyncTask running in a background thread, via an ExecutorService
. Like with a Future
though, it provides a get()
method that will wait for, and return, the result.
new FileParserTask(cities -> {
Assert.assertEquals("Input should give back 200 results", 3, cities.size());
}).execute(file).get();
Upvotes: 0