30

I have an image loader class and i need to test some static methods in it. Since Mockito does not support static methods i switched to Power Mockito. But the static method i am testing has a method call

 Base64.encodeToString(byteArray, Base64.DEFAULT);

To mock this i am using mockStatic method as below with @PrepareForTest annotation.

 PowerMockito.mockStatic(Base64.class);

But Android studio is returning me still returning me an error as below.

org.powermock.api.mockito.ClassNotPreparedException: The class android.util.Base64 not prepared for test. To prepare this class, add class to the '@PrepareForTest' annotation.

Below is my complete code.

Code to be tested:

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import android.widget.ImageView;

  public static String convertBitmapToBase64(Bitmap imageBitmap, boolean withCompression) {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    imageBitmap.compress(Bitmap.CompressFormat.PNG, 120, byteArrayOutputStream);
    byte[] byteArray = byteArrayOutputStream.toByteArray();
    return Base64.encodeToString(byteArray, Base64.DEFAULT);
}

Test class code

import android.graphics.Bitmap;
import android.util.Base64;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.testng.annotations.Test;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Base64.class})
public class ImageLoaderTest  {
@Test
   public void testConvertBitmap(){
    byte[] array = new byte[20];
    PowerMockito.mockStatic(Base64.class);
    PowerMockito.when(Base64.encodeToString(array, Base64.DEFAULT)).thenReturn("asdfghjkl");
    Bitmap mockedBitmap= PowerMockito.mock(Bitmap.class);
    String output = ImageLoaderUtils.convertBitmapToBase64(mockedBitmap);
    assert (!output.isEmpty());
}

}

Gradle dependencies

testCompile 'junit:junit:4.12'
testCompile 'org.powermock:powermock:1.6.5'
testCompile 'org.powermock:powermock-module-junit4:1.6.5'
testCompile 'org.powermock:powermock-api-mockito:1.6.5'
Ajith M A
  • 3,838
  • 3
  • 32
  • 55
  • show us your import – JEY Sep 21 '16 at 08:31
  • @JEY Imports added. Both the test class and class to be tested are using same imports. – Ajith M A Sep 21 '16 at 08:55
  • 2
    are you using junit or testng ? because the test annotation is imported from TestNG. – JEY Sep 21 '16 at 09:01
  • @JEY I changed the import from TestNG to Junit and now i am getting the error as below. " =============================================== Default Suite Total tests run: 0, Failures: 0, Skips: 0 =============================================== Process finished with exit code 0 Empty test suite. " I am not sure which testing framework to use. – Ajith M A Sep 21 '16 at 12:03
  • take a look at https://developer.android.com/studio/test/index.html to understand how to create unit test and run them. – JEY Sep 21 '16 at 12:20

3 Answers3

18

Short answer you can't. Here from the FAQ:

What are the limitations of Mockito

  • Cannot mock final classes
  • Cannot mock static methods
  • Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.

Further information about this limitation:

Can I mock static methods?

No. Mockito prefers object orientation and dependency injection over static, procedural code that is hard to understand & change. If you deal with scary legacy code you can use JMockit or Powermock to mock static methods.

If you want to use PowerMock try like this:

@RunWith(PowerMockRunner.class)
@PrepareForTest( { Base64.class })
public class YourTestCase {
    @Test
    public void testStatic() {
        mockStatic(Base64.class);
        when(Base64.encodeToString(argument)).thenReturn("expected result");
    }
}

EDIT: In Mockito 2 it's now possible to mock final Class and final Method. It's an opt-in option. You need to create the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker with the following content:

mock-maker-inline

EDIT 2: Since Mockito 3.4.0 its now possible to mock static method too:

try (MockedStatic mocked = mockStatic(Base64.class)) {
    mocked.when(() -> Base64.encodeToString(eq(array), eq(Base64.DEFAULT))).thenReturn("bar");
    assertEquals("bar", Base64.encodeToString(array, Base64.DEFAULT));
    mocked.verify(() -> Base64.encodeToString(any(), anyIn());
}

Furthermore you can directly add as a dependency org.mockito:mockito-inline:+ and avoid manually create the or.mockito.plugins.MockMaker file

Since Mockito 3.5.0 you can also mock object construction.

Nantoka
  • 4,174
  • 1
  • 33
  • 36
JEY
  • 6,973
  • 1
  • 36
  • 51
  • 3
    This answer is not at all useful. You basically restated what the question mentioned: "Since Mockito does not support static methods i switched to Power Mockito" and then in your mentioning of PowerMock you give an example that basically repeats what he has in the question's sample code. – Jason White Jul 11 '19 at 21:38
  • 1
    Well the question has been edited multiple time to include part of my answer over time. You can down vote it. – JEY Jul 12 '19 at 01:52
  • 1
    My apologies, I should have considered that the question was edited before adding my critique. – Jason White Jul 25 '19 at 21:47
0

Based on your imports, you are using TestNG framework for your test and Junit module for PowerMock. I think that's where the conflict arises. You can follow this https://www.baeldung.com/intro-to-powermock article to setup Junit4 to work with powermock. Or you may need to google setup TestNG to work with powermock if you intend to keep using TestNG as your testing framework.

0

I faced a similar issue and fixed it by extending the class with PowerMockTestCase.

@RunWith(PowerMockRunner.class)
@PrepareForTest({Base64.class})
public class ImageLoaderTest extends PowerMockTestCase{

}
Coder17
  • 767
  • 4
  • 11
  • 30