I have a legacy class which has a static void method which i need to test:
public class A {
public static void renameTo()
{
String ext = "." + this.fileName + ".backup";
for (File file : getCSVFile()) {
f.renameTo(new File(file.getAbsolutePath() + ext));
}
public static File[] getAllFiles()
{
//logic to read the CSV files from the class path
}
}
Now I have written a test case for it using PowerMockito which looks like this. Now the issue is, even though the renameTo() is called only, if i call PowerMockito.verifyStatic( Mockito.times(10)) the test still passes
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
#PowerMockIgnore("javax.management.*")
public class ATest {
#Test
public void testRenameTo() throws Exception {
PowerMockito.mockStatic(A.class);
A.renameTo();
PowerMockito.verifyStatic( Mockito.times(1));
//PowerMockito.verifyStatic( Mockito.times(5));//Passes even though the mehod is called only once
//PowerMockito.verifyStatic( Mockito.times(10);//Passes even though the mehod is called only once
}
}
Could someone please shed some light into this issue? what I may be doing wrong?
As per the documentation, after the test verifyStatic needs to be called first, then call A.renameTo() to tell it which static method to verify. Example:
// run test
A.renameTo();
// verify interaction
PowerMockito.verifyStatic(A.class, Mockito.times(1));
A.renameTo();
Related
So I'm using MockedStatic<> to mock a static method but it seems like the item inside is still getting called? If this is the case, what's the point of mocking it? I have the following setup:
Object being tested:
public class ObjectBeingTested {
public void methodBeingTested() {
Object obj = ObjectInQuestion.getInstance(new Object(), "abc");
// do stuff with obj
}
}
The object with static method:
public class ObjectInQuestion {
public static ObjectInQuestion getInstance(Object obj, String blah) {
someLocalVar = new FileRequiredObject();
// we get NullPointerException here cuz in test env, no files found
}
private ObjectInQuestion() {
// private constructor to make people use getInstance
}
}
Test code:
public class MyTestClass {
MockedStatic<SomeClass> mySomeClass;
#Mock ObjectInQuestion mMockedObjectInQuestion;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mySomeClass = mockStatic(SomeClass.class);
when(SomeClass.getInstance(any(), anyString()).thenReturn(mMockedObjectInQuestion);
}
#After
public void tearDown() {
mySomeClass.close();
}
}
My questions are the following:
Why calling ObjectInQuestion.getInstance() in the test class, it's totally fine but when it's being called from ObjectBeingTested, it runs the real construction?
I tried to use mockConstruction on FileRequiredObject, it still actually construct the object ... why?
You're using the wrong syntax for stubbing the static method. You want something like
mySomeClass.when(
()->SomeClass.getInstance(any(), anyString()))
.thenReturn(mMockedObjectInQuestion);
More information available here
Assuming MockedStatic<SomeClass> mySomeClass; is actually MockedStatic<ObjectInQuestion> mySomeClass;, I would try to simplify the setup using a classic try block.
In any case, sharing the actual test method might be able to shine some light. ;)
There are considerable answers around, that seem to address this topic, but somehow it is never working out for me. I must be making some mistake, somewhere.
I have this class.
public class myClass {
public static void myEdit(boolean flag) throws Exception {
if (flag) {
System.out.println("Wow!");
} else {
PortalBL.mySave(flag);
}
}
public static void mySave(boolean wtv) throws Exception {
System.out.println("Doesn't matter");
}
}
I want to write a simple unit test, where I call myEdit, with flag = false. I just want the test to pass if it confirms that the PortaBL.mySave was called. I don't want it to be executed, I just want to verify if it was called.
I am trying to do it like this:
#Test
public void myTest() throws Exception {
try (MockedStatic<PortalBL> mock = Mockito.mockStatic(PortalBL.class)) {
mock.when(() -> PortalBL.mySave(anyBoolean())).thenAnswer((Answer<Void>) invocation -> null);
PortalBL.myEdit(false);
mock.verify(() -> PortalBL.mySave(anyBoolean()));
}
}
The idea would be to mock the static method, so that I can handle it without executing it and later verify that it was called, when I call PortalBL.myEdit
I believe that the class is badly written. It shouldn't be static method, I should be instantiating this class as an object and carry on. But, let's say that we are determined to test this particular scenario, as it is. Is it possible?
Btw, when I execute the PortaBL.myEdit(false) line, it isn't truly executed. I believe it is because the machine is thinking it is a mock, and doesn't know what to do with it when it is called..
I have a function that I use to detect whether a certain directory path exists. Here's the function:
public boolean isRunningOnSandbox() {
return Files.isDirectory(Paths.get("/mySandbox/cloud/sandbox"));
}
As you can see, it relies on static method isDirectory. In my team, we do not use PowerMock for testing.
So, how can I test this method? I have tried writing a test like:
#Rule
public TemporaryFolder temporaryFolder;
#Test
public void test() throws IOException {
File parent = new File("/");
temporaryFolder = new TemporaryFolder(parent);
temporaryFolder.create();
File folder = temporaryFolder.newFolder("mySandbox", "cloud", "sandbox");
subject.isRunningOnSandbox();
}
But, I get an error
ava.io.IOException: Permission denied
because it doesn't let me create a temporary folder under the root. I am guessing there is a better way to test this code instead of trying to create a folder.
There are many ways to do it, onee of them migh be like the below one.
Assumming that isRunningOnSandbox method is in some class SomeClass, then refactor this class in this way:
public class SomeClass {
public boolean isRunningOnSandbox() {
return Files.isDirectory(Paths.get(getSanboxPath()));
}
protected String getSanboxPath(){
return "/mySandbox/cloud/sandbox";
}
}
and then in your tests inject into this class another directory to which you have access, for example:
public class SomeClassTest {
class SomeClassToTest extends SomeClass{
String folder;
public SomeClassToTest(String folder){
this.folder = folder;
}
#Override
protected String getSanboxPath(){
return folder;
}
}
static String sandboxFolder = "myTestSandobxFolder";
static Path tempDir;
#BeforeClass
public static void createFolder() throws IOException {
tempDir = Files.createTempDirectory(sandboxFolder);
}
#AfterClass
public static void deleteFolder() throws IOException {
Files.delete(tempDir);
}
#Test
public void IsRunningOnSandbox_shouldReturnTrueWhenPathExists() throws IOException {
//given
SomeClass testedObject = new SomeClassToTest(tempDir.toString());
//when
boolean result = testedObject.isRunningOnSandbox();
//then
assertThat(result).isTrue();
}
#Test
public void IsRunningOnSandbox_shouldReturnFalseWhenPathDoesNotExist() throws IOException {
//given
SomeClass testedObject = new SomeClassToTest("/abcdef123");
//when
boolean result = testedObject.isRunningOnSandbox();
//then
assertThat(result).isFalse();
}
}
The function you have shown is not suited for unit-testing: With unit-testing you try to find the bugs in small, isolated software pieces. But, which bugs could be in this example code that are not related to the other components, that is, the Files component, the Paths component and the actual file system?
The potential bugs in your example are about questions like "am I calling the right functions?" or "do I call the functions with proper values for the arguments?" or "do the functions I call return arguments as I expect" or "am I using the path that is also the path found in the file system". This can not be checked with unit-testing, but with integraton-testing.
Imagine you have the wrong path in mind. Then, in your unit-test you would also check against the same wrong path, and your unit-test would succeed. Only when running that test as an integration test on the real file system you could figure out that the path which you had in mind was wrong and did not match the actual path in the file system.
I have a method in my utilities:
public void createDirectories(final Path root, final Scaffolding scaffolding) throws FileAlreadyExistsException {
if (Files.exists(root)) {
throw new FileAlreadyExistsException("Root directory " + root.toString() + " already exists.");
} else {
Files.createDirectories(root);
// Create directories from the scaffolding object
}
}
I want to mock Files so I can test to make sure Files.createDirectories with the expected fields are called or not.
Can I do this with Mockito? Or do I need to actually create the directories and check for their existence in some tmp folder?
When you write something with tdd and have troubles consider it as signal of bad design. You don't need to mock static fields or find some tricky lib for do it. Instead of doing this make entity that represent filesystem and place all methods related to file operations to this class. With this refactor your code will be like that:
class UtilClass { //util classes are bad don't do it
private final FileSystem fileSystem;
public UtilClass(FileSystem fileSystem) {
this.fileSystem = fileSystem;
}
public void createDirectories(final Path root, final Scaffolding scaffolding) throws FileAlreadyExistsException {
if (fileSystem.exists(root)) {
throw new FileAlreadyExistsException("Root directory " + root.toString() + " already exists.");
} else {
fileSystem.createDirectories(root);
// Create directories from the scaffolding object
}
interface FileSystem {
boolean exists(Path path);
void createDirectories(Path path);
}
and test class
class UtilClassTest {
#Test(expected = FileAlreadyExistsException.class)
public void shouldThrowExceptionWhenRootPathExists() {
FileSystem mockFileSystem = Mockito.mock(FileSystem.class);
Mockito.when(mockFileSystem.exists(anyPath())).return(true);
UtilClass util = new UtilClass(mockFileSystem);
util.createDirectories(mock(Path.class), mock(Scaffolding.class))
}
}
In your code outside tests replace mock to implementation.
class FileSystemImpl implements FileSystem {
boolean exists(Path path){
return Files.exists(path);
}
createDirectories(Path path){
return Files.createDirectories(path);
}
}
and you don't need to touch file system in tests or mock static fields.
I'm sending you an example, which allows you to use the FileSystems Mock in a transparent way
#Test
#ExtendWith(MockfsExtension.class)
void testExecute_MockFSNew(FileSystem fileSystem) throws Exception {
Path master = Files.createDirectories(Paths.get("/fakedir/conf/java/rest/master"));
Path homologacao = Files.createDirectories(fileSystem.getPath("/fakedir/conf/java/rest/homologacao"));
Path dev = Files.createDirectories(fileSystem.getPath("/fakedir/conf/java/rest/dev"));
}
Paths.get return a mock fs, this is done using Mockito.mockStatic
It's also injecting FileSystem in paramter
using
package br.com.pulse.starter.builder.steps.impl;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder;
public class MockfsExtension implements BeforeEachCallback, AfterEachCallback , ParameterResolver {
MockedStatic<FileSystems> mock;
private FileSystem fileSystem;
public FileSystem getFileSystem() {
return this.fileSystem;
}
#Override
public void beforeEach( ExtensionContext context ) throws Exception {
this.fileSystem = MemoryFileSystemBuilder.newEmpty().build();
mock = Mockito.mockStatic(FileSystems.class);
mock.when(() -> FileSystems.getDefault()).then(invocation -> {
System.out.println("Requested FakeFs >>>");
return fileSystem;
});
}
#Override
public void afterEach( ExtensionContext context ) throws Exception {
if (this.fileSystem != null) {
this.fileSystem.close();
}
mock.close();
}
#Override
public boolean supportsParameter( ParameterContext parameterContext , ExtensionContext extensionContext ) throws ParameterResolutionException {
return true;
}
#Override
public Object resolveParameter( ParameterContext parameterContext , ExtensionContext extensionContext ) throws ParameterResolutionException {
return this.fileSystem;
}
}
See:
https://github.com/marschall/memoryfilesystem
https://github.com/marschall/memoryfilesystem/issues/130
You cannot mock static methods with base Mockito, nor, in most cases, should you be, especially one provided by Java. You can mock static methods with PowerMock, but this is a Global core library.
The piece of code you are testing here is whether or not you get an exception if the directory exists. If Files.exists() is returning bad results, your program is toast either way. So what you should ultimately be testing is that the flow is being properly followed while depending on a fully implemented Files global.
#Test
public void testCreateDirectories() {
File tempFile = new File("test");
tempFile.delete(); //delete test directory if it exists
tempFile.deleteOnExit(); //and again when the test finishes
Path testPath = tempFile.getPath();
foo.createDirectories(testPath, mock(Scaffolding.class)); //should create path
Assert.assertTrue(tempFile.exists());
try {
foo.createDirectories(testPath, mock(Scaffolding.class)); //should FAE
Assert.fail(Should have thrown an FAE exception at this point!);
}
catch(FileAlreadyExistsException faee) {
logger.debug("Expected FAE exception thrown", faee);
}
}
This execution will go through both the true and false path and clean up after itself.
This double execution of the logic tests both paths and is designed to cover the following scenarios if your if statement manages to get mucked up.
boolean works as intended: both calls work, PASS
boolean is accidentally inverted: 1st call throws FAE, FAIL
boolean always returns false: 2nd call doesn't throw FAE, FAIL.
boolean always returns true: 1st call throws FAE, FAIL.
I have the following class
public final class Foo {
private Foo() {}
public static void bar() {
if(baz("a", "b", new Object())) { }
}
private static boolean baz(Object... args) {
return true; // slightly abbreviated logic
}
}
And this is my Test:
#PrepareOnlyThisForTest(Foo.class)
#RunWith(PowerMockRunner.class)
public class FooTest {
#Test
public void bar() {
PowerMockito.mockStatic(Foo.class); // prepare
Foo.bar(); // execute
verifyPrivate(Foo.class, times(1)).invoke("baz", anyVararg()); // verify - fails
}
}
For that, I get the following error message - and I don't understand why...
Wanted but not invoked com.example.Foo.baz(
null );
However, there were other interactions with this mock.
Removing the prepare line above seems to make the verify line pass no matter for how many times you check for... :(
(Our SONAR code checks enforce that each test has some sort of assertXyz() in it (hence the call to verify()) and enforces a very high test coverage.)
Any ideas how to do this?
The problem with your code is that you mock Foo so your method implementations won't be called by default such that when you call Foo.call() it does nothing by default which means that it never avtually calls baz that is why you get this behavior. If you want to partially mock Foo, mock it using the option Mockito.CALLS_REAL_METHODS in order to make it call the real methods as you seem to expect, so the code should be:
#PrepareOnlyThisForTest(Foo.class)
#RunWith(PowerMockRunner.class)
public class FooTest {
#Test
public void bar() throws Exception {
PowerMockito.mockStatic(Foo.class, Mockito.CALLS_REAL_METHODS); // prepare
...
}
}