Why do I get a Reflection exception NoSuchMethodException if the tests runs fine

1.6k views Asked by At

I'm using Reflection to Mock a private method (I don't want to discuss if that makes sense or not).

Anyone know why? I'll let my testClass source code here it may help. I've tryed much of the Internet helps and ways to solve this but none have worked for me.

public class testProtexManagerProcessRequiredFile {

  @Mock
  ProtexManager PxManager;


  @Before
  public void inicializa() {
    MockitoAnnotations.initMocks(this);
  }

  @Test
  public void processRequiredFileTest() throws ClassNotFoundException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, InstantiationException {

    Method method;
    try {
      method = ProtexManager.class.getDeclaredMethod("processRequiredFile", File.class);
      method.setAccessible(true);

      File FileExample = new File();
      String NameExample = "Nome";
      File outputs = new File();
      outputs = (File) Mockito.when(method.invoke(PxManager, FileExample,NameExample)).thenReturn(FileExample);
      assertNotNull(outputs);
      assertEquals(outputs, method.invoke(PxManager, FileExample,NameExample));
    } catch (NoSuchMethodException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
   System.out.println("Teste Concluido."); 
  }
}

That's the method code:

 private File processRequiredFile(File file, String name) {
    if (!file.exists()) {
      this.message = name + " file not found at location: " + file;
      this.msgResponse.addMsgList(MsgCode.FAILURE, MsgLevel.ERROR, this.message, StringUtils.EMPTY);
    }
    return file;
  }

And thank you all for helping me in my doubts.

2

There are 2 answers

0
Lothar On

What is your actual question? Why the testcase succeeds? That's already answered in the comments. You catch the exception and essentially ignore it. If you want to see the stacktrace on STDERR and let the testcase fail, you have to initiate the failing procedure yourself, e.g by calling

throw (AssertionFailedError) new AssertionFailedError("method not found").initCause(e);

This construct looks strange but JUnit 3 (I assume you're using that given your code) doesn't come with an AssertionFailedError with a constructor allowing to pass a cause. This way you see the stacktrace in your IDE as well and will be visible in JUnit-reports created during build processes.

Or is your question why the particular method is not found? One reason can be that someClass.getDeclaredMethod only returns a result if the method is declared in that particular class. If that class has a super class inheriting this method, you have to use the superclass when calling getDeclaredMethod to get the method.

If you don't know what class actually contains a method you have to iterate over all superclasses until reaching the "end":

Class<?> clazz = ProtexManager.class;
while (clazz != null) {
    try {
        return clazz.getDeclaredMethod("processRequiredFile", File.class);
    catch(NoSuchMethodException e) {
        clazz = clazz.getSuperClass();
    }
}

That code block swallows the NoSuchMethodException but I don't want to do things more complicated than necessary to illustrate the idea.

Another reason why the method is not found might be that the class in question has a method processRequiredFile(java.io.File) and not processRequiredFile(com.blackducksoftware.sdk.codecenter.deeplicense.data.File). Also you later call the method by method.invoke using three parameters (PxManager, File, String) so either your call of getDeclaredMethod is missing parameter classes or your call of invoke will later fail due to the differences between declaration of the method and passed parameters.

0
AudioBubble On

To answer your question,

Because you caught the NoSuchMethodException. To get a test failure you have to somehow get some exception or error during the test execution


To follow up on the comments, here's how one can test this method:

// let's assume there are getter for this.message / this.msgResponse 
// and this method is in the class foo.bar.Foobar
protected File processRequiredFile(File file, String name) {
    if (!file.exists()) {
      this.message = name + " file not found at location: " + file;
      this.msgResponse.addMsgList(MsgCode.FAILURE, MsgLevel.ERROR, this.message, StringUtils.EMPTY);
    }
    return file;
}

In a test class foo.bar.FoobarTest:

@Mock
private File file;

private Foobar foobar = new Foobar(); 

@Test
public void testWithNonExistingFile() {
    Mockito.when(this.file.exists()).thenReturn(false); // this is to illustrate, you could also use some non existent file: new File("/does-not-exists.foo")
    File result = this.foobar.processRequiredFile(this.file, "some name");
    assertThat(result).isEqualTo(this.file);
    assertThat(foobar.getMsgResponse()).isNotEmpty(); // TODO: better assertion
    assertThat(foobar.getMessage()).isEqualTo( "some name file not found at location: " + this.file);
}

@Test
public void testWithExistingFile() {
    Mockito.when(this.file.exists()).thenReturn(true);
    File result = this.foobar.processRequiredFile(this.file, "some name");
    assertThat(result).isEqualTo(this.file);
    assertThat(foobar.getMsgResponse()).isEmpty();
    assertThat(foobar.getMessage()).isNull();
}

The class under test (i.e. Foobar) is really tested, this uses a real instance of it and call its method. A mock is used to replace something we don't have (here it's a file to illustrate but it's usually something more complicated)