djthoms
djthoms

Reputation: 3096

PowerMock UnfinishedStubbingException error on final class

Trying to get Mockito and PowerMock to behave, but I'm getting an UnfinishedStubbingException when trying to run this code:

@RunWith(PowerMockRunner.class)
@PrepareForTest(FileIOHelper.class)
public class FileIOHelperTest {

    @Test
    public void testIOExceptionOnWrite() {
        PowerMockito.mockStatic(FileIOHelper.class);
        PowerMockito.doThrow(new IOException()).when(FileIOHelper.class);
        PowerMockito.verifyStatic();
        FileIOHelper.write(Mockito.anyString(), Mockito.anyString());
    }

    @After
    public void validate() {
        Mockito.validateMockitoUsage();
    }

}

and this IO class

public final class FileIOHelper {

    public static void write(final String file, String message, final boolean appendNewLine) {
        if(checkArgs(file, message)) {
            final Path path = Paths.get(file);
            StandardOpenOption mode = StandardOpenOption.APPEND;
            if(Files.notExists(path)) {
                mode = StandardOpenOption.CREATE_NEW;
            }
            if(appendNewLine) {
                message += System.getProperty("line.separator");
            }
            try {
                Files.write(path, message.getBytes(), mode);
            } catch(IOException e) {
                handleException(e, "Problem writing to " + file);
            }
        }
    }

    private static boolean checkArgs(final String... args) {
        if(args != null && args.length > 0) {
            for(final String arg : args) {
                if(arg == null || arg.isEmpty()) {
                    return false;
                }
            }
        }

        return true;
    }

    private static void handleException(final IOException e, final String errorMsg) {
        handleException(e, errorMsg, true);
    }

    private static void handleException(final IOException e, final String errorMsg, final boolean printStace) {
        checkArgs(errorMsg);

        System.err.println(errorMsg);
        System.err.println(e.getMessage());

        if(printStace) {
            e.printStackTrace();
        }
    }

}

What I want to do is somehow trigger the IOException so handleException can be tested. Why one might ask? I'm looking at my Jacoco report and I see this:

jacoco report

I've looked at:

and I'm still completely lost. I have no idea if I need to trigger the IOException or if I can somehow verify the output of handleException without doThrow. Someone, help!

Error log:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at FileIOHelperTest.testIOExceptionOnWrite(FileIOHelperTest.java:8) // doThrow line

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, you naughty developer!
 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

Upvotes: 0

Views: 798

Answers (3)

Rodrigo Villalba Zayas
Rodrigo Villalba Zayas

Reputation: 5616

First, you have to mock the class 'Files', not 'FileIOHelper'. FileIOHelper is the tested class. Second, you didn't specified which method should throw IOException. The unit test method should be as follows (supposing the tested method catches and manage the IOException):

@RunWith(PowerMockRunner.class)
@PrepareForTest(Files.class)
public class FileIOHelperTest {

  @Test
  public void testIOExceptionOnWrite() {
     PowerMockito.mockStatic(Files.class);
     PowerMockito.doThrow(new IOException()).when(Files.class);
     Files.write("path", "message", true);
     FileIOHelper.write("path", "message", true);
     PowerMockito.verifyStatic();
     Files.write("path", "message", true);
  }
}

Upvotes: 0

asch
asch

Reputation: 1963

  1. First of all, IOException is checked exception - it should be declared with throws in the method signature. But your method FileIOHelper.write does not have such. This may be the reason of the UnsutisfiedStubbingException.
  2. I do not understand, what your are trying to test: if the FileIOHelper is a mock - handleException will be never called, since it is called by the real write method, not by mocked.

Upvotes: 0

GhostCat
GhostCat

Reputation: 140457

My recommendation: forget about using PowerMock.

If you have to mock static methods, then build your own little wrapper class around that. Then, for testing, your wrapper can return something you control; and for production usage; your wrapper just calls the static method.

PowerMock looks like the solution to many problems; but rather sooner than later, it will be the cause of much more problems. It breaks coverage, it makes it harder to change the underlying JVM, and so on.

Seriously: if your design can only be tested with PowerMock, this is very often a clear indication that your design is bad. So: focus on reworking your code under test; instead of investing time into a tool like PowerMock that does more harm than good.

I have spent countless hours trying to resolve PowerMock problems; and since I started to instead write "better to test" production code ... I have written hundreds or thousands of tests without ever needing PowerMock again.

In your case: start by avoiding static all over the place. Basically you achieve that by (worst case) pulling little wrapper classes around the static calls you have to make. For testing, you can mock the wrapper object; and in production code, you use dependency injection to provide a (singleton/enum) wrapper object that simply makes the static call.

Upvotes: 1

Related Questions