flutterflutter-testend-to-endflutter-exception

Flutter Image.network test fails because of exception


I use Image.network to display images of items:

Image.network(
  pictureUri,
  errorBuilder: (context, error, stackTrace) => Image.asset(
    noPictureAssetUri,
  ),
);

when given item has an image, then the server returns that image, if the item has no image, then the server returns error 404.

It works fine in release mode - if there is image, it is displayed, and if server sends 404, then it uses the asset.

However when I'm running integration tests (flutter test integration_test), they show:

══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════ The following NetworkImageLoadException was thrown resolving an image codec: HTTP request failed, statusCode: 404,

and then it fails:

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ The following message was thrown: Multiple exceptions (5) were detected during the running of the current test, and at least one was unexpected.

The tests fails despite everything working as intended.

How can I make my tests pass? I need either:

I want to add that this is an end to end test, running on real (development) server, so I can't just mock http Client as it was suggested. I need a way to handle 404 error, when the real server returns it in debug mode.

My flutter doctor, in case you need it:

Doctor summary (to see all details, run flutter doctor -v):

[√] Flutter (Channel stable, 3.3.10, on Microsoft Windows [Version 10.0.22621.963], locale en-150)

[√] Android toolchain - develop for Android devices (Android SDK version 33.0.0)

[√] Chrome - develop for the web

[√] Android Studio (version 2021.2)

[√] VS Code (version 1.74.2)

[√] Connected device (4 available)

[√] HTTP Host Availability


Solution

  • I have not found a direct answer to this question. It seems that internally Image.network will always raise an exception in this situation which will stop the debug mode app.

    Thus the only way to run an integration test with a non-mocked database is to circumvent the image-loading altogether. One method to do this is when you run an integration test and you create an instance of the app, you pass some parameter that tells the app that this is, in fact, a test, e.g. app.main(isTestMode: true);. Then you make an if to load a static asset when the app is in the test mode:

    if (MyApp.isTestMode)
    {
        return Image.asset(...);
    }
    else
    {
        return Image.network(...);
    }
    

    The obvious drawback of this method is that it does not allow you to test if images load correctly during the test, but it's better than nothing.