Search code examples
androidunit-testingjunitmockitopowermockito

How to test a static method using mock() and spy()


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);
}

Solution

  • 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.