the below posted method in the code section contains a static method which is "with()". I want to test the code in below, so I coded the test of this method as shown in the testing section.
i tried to test the method using both of "spy()" and "mock()" but the test fails alwyas.
please let me know how can I test a method returns void?
code
public RequestCreator requestCreatorFromUrl(String picUrl) {
return Picasso.with(mCtx).load(picUrl);
}
testing:
public class ValidationTest {
@Mock
private Context mCtx = null;
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
@Before
public void setUp() throws Exception {
mCtx = Mockito.mock(Context.class);
Assert.assertNotNull("Context is not null", mCtx);
}
@Test
public void whenRequestCreatorFromUrlTest() throws Exception {
Picasso picasso = Picasso.with(mCtx);
Picasso spyPicasso = spy(picasso);
Uri mockUri = mock(Uri.class);
RequestCreator requestCreator = Picasso.with(mCtx).load(mockUri);
RequestCreator spyRequestCreator = spy(requestCreator);
doReturn(spyRequestCreator).when(spyPicasso.load(mockUri));
//when(spyPicasso.load(mockUri)).thenReturn(spyRequestCreator);
RequestCreator actual = spyPicasso.load(mockUri);
Assert.assertEquals(requestCreator, actual);
}
With Spy in Mockito, we can eliminate the additional code ItemServiceForTest introduced previously in our test. However, we still need to refactor the production code to override the static method.
There are three ways to test the code that calls static methods: Create a wrapper class and use dependency injection. Use a static Func property. Use the Extract and override call.
Since static method belongs to the class, there is no way in Mockito to mock static methods. However, we can use PowerMock along with Mockito framework to mock static methods.
Spies are useful when we have a huge class full of methods, and we want to mock certain methods. In this scenario, we should prefer using spies rather than mocks and stubs. It calls the real method behavior, if the methods are not stubbed. In Mockito, spy() method is used for creating spy objects.
Usually, if you end up using PowerMock
, that’s a good sign that you most possibly are on the wrong way.
What if instead of directly referring to Picasso
, you create a component, whose responsibility will be to load an image, let's say class ImageLoader
. What will this give to you?
Separation of concerns: if tomorrow you decide to move to Glide
, you shouldn't change each and every class where you were using Picasso
, you will just change implementation of ImageLoader
. Other components are non-wiser of these changes, because they are dependent on an abstraction, not on implementation
Seam: this will allow you easily mock dependencies in order to perform unit testing
This will be our abstraction:
interface ImageLoader {
RequestCreator load(String url);
}
Let’s provide an implementation:
class ImageLoaderImpl implements ImageLoader {
private final Picasso picasso;
public ImageLoaderImpl(Context context) {
this.picasso = Picasso.with(context);
}
@Override
public RequestCreator load(String url) {
return picasso.load(url);
}
}
Now, in your components whenever you need Picasso
use ImageLoader
instead.
Thus, your method becomes following:
public static RequestCreator requestCreatorFromUrl(String picUrl) {
return imageLoader.load(picUrl);
}
Then your test will look like this:
@Test
public void test() {
ImageLoaderImpl imageLoader = Mockito.mock(ImageLoaderImpl.class);
RequestCreator expected = Mockito.mock(RequestCreator.class);
String TEST_URL = "https://www.some.url/img.jpg";
when(imageLoader.load(TEST_URL)).thenReturn(expexted);
RequestCreator actual = clazzToTest.requestCreatorFromUrl(TEST_URL);
assertEquals(expected, actual);
}
No mocking of static
method, no PowerMock
needed.
From the Mockito's FAQ:
What are the limitations of Mockito
...
Cannot mock static methods
Use PowerMock instead. Here you will find the detailed instruction about how to mock the static methods.
Update
In order to apply the PowerMock to your test you need to:
Add @PrepareForTest
at test class level:
@PrepareForTest(Picasso.class)
public class ValidationTest {
...
}
Call PowerMockito.mockStatic()
to mock a static class
PowerMockito.mockStatic(Picasso.class);
Just use Mockito.when()
to setup your expectation:
Mockito.when(Picasso.with(mCtx)).thenReturn(requestCreator);
The same set of steps is applicable for the RequestCreator.class
.
P.S. I can make mistakes because I do not know the API of 3rd party library you use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With