Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use OkHttpClient MockWebSever to return an image/byte[]?

I'm working on an android library project, where I need to download an PNG image from a REST service, transform it into a Bitmap and return it to the app(s) using this library. So, we have a REST webservice that returns the bytes of a png image. We're calling this service using Retrofit with rxJava. In my code below accessRemoteComm.getImage() does the loading and transformation from ResponseBody to Bitmap inside a .map on the Observable. The image loads fine in the application. I now want to unit test that method, but I'm having a hard time getting MockWebServer to deliver the image in the first place. The OnError is called constantly with:

java.lang.RuntimeException: Method decodeStream in android.graphics.BitmapFactory not mocked. See http://g.co/androidstudio/not-mocked for details.

This is what I have so far:

Retrofit interface:

@GET("webapi/user/{ID}/image")
Observable<ResponseBody> getVehicleImage(
        @Path("ID") @NonNull final String id,
        @Query("width") @NonNull final int width,
        @Query("height") @NonNull final int height,
        @Query("view") @NonNull final ImageView view
);

getImage() Method:

public Observable<Bitmap> getVehicleImage(@NonNull String id, @NonNull Integer width, @NonNull Integer height, @NonNull ImageView view) {
    return service.getImage(id, width, height, view).map(new Func1<ResponseBody, Bitmap>() {
        @Override
        public Bitmap call(ResponseBody responseBody) {
            BufferedInputStream isr = new BufferedInputStream(responseBody.byteStream());
            return BitmapFactory.decodeStream(isr);
        }
    });
}

My test method:

@Test
public void testGetVehicleImage() throws Exception {

    String path = basePathForImages + "vehicleTestImage.png";

    Source pngSource = Okio.source(new File(path));

    BufferedSource bufferedSrc = Okio.buffer(pngSource);

    server.enqueue(new MockResponse()
            .setResponseCode(200)
            .setHeader("Content-Type", "image/png")
            .setBody(bufferedSrc.buffer()));

    Subscriber<Bitmap> subscriber = new Subscriber<Bitmap>() {
        @Override
        public void onCompleted() {
            Log.d("OnComplete");
        }

        @Override
        public void onError(Throwable e) {
             Log.d(e.toString());
             //java.lang.RuntimeException: 
             //Method decodeStream in android.graphics.BitmapFactory not mocked.
        }

        @Override
        public void onNext(Bitmap bitmap) {
            Log.d("Yeeee");
        }
    };

    Observable<Bitmap> observable = accessRemoteCommVehicle.getVehicleImage("abc", 0, 0, VehicleImageView.FRONT);

    observable.toBlocking().subscribe(subscriber);
}

I'm pretty sure, that I don't setup the bufferedSource correctly. But I cannot find any resources on SO or the web that shows the usage of the MockResponse with a Buffer as body. And this is the part, where any help is appreciated. How do I set this up correctly?

Btw. If you have any other suggestion on how to test this, please let me know!

Thank you!

like image 719
ASP Avatar asked Jun 02 '16 05:06

ASP


People also ask

How do you test for OkHttp?

The recommended way of testing your code that uses OkHttp is to utilise their MockWebServer utility. This allows the execution of tests in a realistic operation with full control of responses being passed to the client.


2 Answers

I am currently using this with MockWebServer and seems to work, but could use some mileage. Would be beneficial to the community if you try it and feed back your result.

         import okio.Buffer;
         private final static String TAG = "MYCLASS";
         public static String extPathToPngFile = Environment.getExternalStorageDirectory().getPath() + "/some-icon.png";

         Buffer responseBody = getBinaryFileAsBuffer(extPathToPngFile);

                             ... context removed for brevity ...

         new MockResponse().setResponseCode(200).addHeader("Content-Type:image/png").setBody(responseBody);

        //Buffer wrap a binary file to return with a mock.
        public static Buffer getBinaryFileAsBuffer(String path) throws IOException {
                        File file = new File(path);
                        byte[] fileData = FileUtils.readFileToByteArray(file);
                        Buffer buf = new Buffer();
                        buf.write(fileData);
                        Log.d(TAG, "BUFFER SIZE FOR "+path+" IS:" + buf.size());
                        return buf;
                    }
like image 54
Michael Lupo Avatar answered Nov 15 '22 03:11

Michael Lupo


android.graphics.BitmapFactory is part of Android SDK, so it's available on device/emulator only. In your case your are running unit tests on your host machine (where your code gets compiled), Android SDK classes are not available in that environment. Judging by the error you use Mockito to mock calls to SDK but decodeStream method is not mocked.

There a couple of ways you could approach this:

  1. Use Roboelectric (http://robolectric.org/) which allows you to call to Android Framework methods on your host machine.
  2. Make your unit test an android test (instrumented test) meaning it will be running on emulator/device. More on that here: https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests
like image 27
Gord Avatar answered Nov 15 '22 04:11

Gord