javaspring-bootmockitopowermockito

PowerMock won't mock static method to throw an Exception in a Spring-Boot application


I realize there are many many very similar questions. I've been through all of them and I still cannot make my code work.

I have a service defined in my Spring-Boot application, just like this:

@Service
public class FileStorageService {
    private final Path fileStorageLocation;

    @Autowired
    public FileStorageService(final FileStorageProperties fileStorageProperties) {
            //FileStorageProperties is a very simple class that right now just holds one String value
            this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
                .toAbsolutePath()
                .normalize();

        try {
            Files.createDirectories(fileStorageLocation);
        } catch (IOException e) {
            // FileStorageException is my custom, runtime exception
            throw new FileStorageException("Failed to create directory for stored files", e);
        }
    }
}

And I want to test scenario, when directory creation fails and thus I need to mock method Files.createDirectories(). My test class looks like this:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.io.IOException;
import java.nio.file.Files;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Files.class})
public class FileStorageServiceTest {
    private static final String UPLOAD_DIR = "uploadDir";

    @Test(expected = FileStorageException.class)
    public void some_test() throws IOException {
        PowerMockito.mockStatic(Files.class);
        PowerMockito.when(Files.createDirectories(Mockito.any())).thenThrow(new IOException());

        new FileStorageService(createFileStorageProperties());
    }

    private FileStorageProperties createFileStorageProperties() {
        final FileStorageProperties fileStorageProperties = new FileStorageProperties();
        fileStorageProperties.setUploadDir(UPLOAD_DIR);
        return fileStorageProperties;
    }
}

I believe I followed every step from tutorials and questions I've read. I use:

  1. @RunWith(PowerMockRunner.class),
  2. @PrepareForTest({Files.class}),
  3. PowerMockito.mockStatic(Files.class),
  4. and PowerMockito.when(Files.createDirectories(Mockito.any())).thenThrow(new IOException());.

Still, no exception is thrown during test and it fails. WIll be super thankful for the help, cause I feel I miss something really simple and just cannot see it.


Solution

  • From: https://github.com/powermock/powermock/wiki/Mock-System

    Normally you would prepare the class that contains the static methods (let's call it X) you like to mock but because it's impossible for PowerMock to prepare a system class for testing so another approach has to be taken. So instead of preparing X you prepare the class that calls the static methods in X!

    Basically, we mock the class's use of the System class, rather than unmockable System class itself.

    @PrepareForTest({Files.class})
    

    An alternative, non-Powermock way to do this without mocking any system class would be to create a helper method, @Spy the original class, and mock that helper method specifically to throw the exception.

    when(spy.doSomethingWithSystemClasses()).thenThrow(new Exception("Foo"));