3

I'm trying to get to grips with JUnit & Mockito etc.

I currently have a method with the below line.

ObjectMetadata metadata = getMetadata(path.toString());

Is there any way I can mock it? I've tried things like the below

Whitebox.setInternalState(<mock of class>, "metadata", "abc");

but I just get

org.powermock.reflect.exceptions.FieldNotFoundException: No instance field named "metadata" could be found in the class hierarchy of com.amazonaws.services.s3.model.ObjectMetadata.

I think it's because previous use of Whitebox.setInternalState was with variables.

Any info. that might get me started would be appreciated.

2 Answers 2

4

If the method is protected then you dont need to use Powermockito, plain vanilla Mockito is enough and spying would do the trick here. Assuming the test class is in the same package as the production one, just in the src/test/java dir.

ClassUnderTest classUnderTestSpy = Mockito.spy(new ClassUnderTest()); // spy the object 

ObjectMetadata objectMetadataToReturn = new ObjectMetadata();

doReturn(objectMetadataToReturn).when(classUnderTestSpy).get(Mockito.any(String.class));

I used any() matcher for the input but you can use a concrete value also.

Update If you cannot see the method then you would need to create an inner class that extends the prod one, implement the get method:

public class Test{

  ObjectMetadata objectMetadataToReturn = new ObjectMetadata();

  @Test
  public void test(){
      ClassUnderTestCustom classUnderTestCustom  = new ClassUnderTestCustom();

      // perform tests on classUnderTestCustom  
  }

  private class ClassUnderTestCustom extends ClassUnderTest{

     @Override
     public String getMetadata(String path){
        return objectMetadataToReturn ;
     }
  }

}
Sign up to request clarification or add additional context in comments.

6 Comments

Is there no way of getting that to work if the test is in a different package? My test is in com.in.stock.sf.col.tests while the production is in com.in.stock.sf.col.
any reason why you not using src/main/java for prod and /src/test/java for testing? and then usnig the same package structure in each?
Sorry, I should have been clear. com.in.stock.sf.col is in src/main/java and com.in.stock.sf.col.tests is in /src/test/java. As for why the sub levels differ, I'm not sure as it was setup by somebody else.
well in theory your Test can extend the prod class and you will have access to that method. Still the proper structure would be the way to go though..
basically if you want to stay with that structure then check my update
|
0
@PrepareForTest(ObjectMetadata.class)
public class PowerMockDemoTest {

    private ObjectMetadata objectMetadata;

    @Before
    public void setUp() {
        objectMetadata = new ObjectMetadata();
    }

    @Test
    public void testMockNew() throws Exception {
        ObjectMetadata mockObjectMetadata = mock(ObjectMetadata.class);

        PowerMockito.whenNew(ObjectMetadata.class)
            .withAnyArguments().thenReturn(mockObjectMetadata);

        ObjectMetadata actualObjectmetadata = getMetadata(path.toString());

        assertThat(actualObjectmetadata, is(mockObjectMetadata));
    }
}

2 Comments

Thanks Sanveet. Does the fact that getMetadata() is protected change anything? I'm getting an error saying "unable to view protected method".
if method getMetadata() is protected method then we need to use reflection API in junit to call that method like below example: Class<?> clazz = mockObjectMetadata.getClass(); Method method = clazz.getDeclaredMethod("getMetadata", String.class); method.setAccessible(true); mockObjectMetadata = (ObjectMetadata) method;

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.