This question has probably been asked a lot of times before. However, I couldn't find answers anywhere. I'm dealing with legacy code here.
Please Note : I'm simplifying my question to get a very specific answer. The code snippets only represent the problem I'm facing. Not the actual code I'm trying to test. The code snippet to be tested here represents part of the overall code I need to test.
Problem : myObj.loadContent(null,null) is actually being called instead of doing nothing as specified with PowerMockito.doNothing().when(mockObj).loadContent(null, null);
Code I wish to unit test :
class ClassInstantiatingObject {
.
.
public static void doSomething(Arg1 arg1, Arg2 arg2) throws Exception{
MyClass myObj = new MyClass(arg1, arg2);
myObj.loadContent(null, null);
}
}
My Unit Test :
import org.junit.Before;
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;
.
.
.
#Test
public void testDoSomething() throws Exception {
MyClass mockObj = PowerMockito.mock(MyClass.class);
PowerMockito.whenNew(MyClass.class).withAnyArguments().thenReturn(mockObj);
PowerMockito.doNothing().when(mockObj).loadContent(null, null);
Arg1 mockArg1 = mock(Arg1.class);
Arg2 mockArg2 = mock(Arg2.class);
StaticClass.doSomething(mockArg1, mockArg2);
}
The code to be tested cannot be changed. Hence, I need a way to actually not call loadContent(null,null) using mockito/powermock.
Also, when using : PowerMockito.doNothing().when(MyClass.class,"loadContent",null,null)
OR PowerMockito.doNothing().when(MyClass.class,"loadContent",Mockito.anyString(),Mockito.anyMap())
I get a java.lang.NullPointerException
at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.addAnswersForStubbing
CORRECT ANSWER
I've managed to figure out the solution. It's very simple to be honest.
In the example specified above. What I was missing was, in case of using PowerMockito.whenNew() , the class that is calling the constructor you wish to mock must be specified in the annotation #PrepareForTest. The class whose constructor you wish to mock need not be specified at all.
For eg.
import org.junit.Before;
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;
#RunWith(PowerMockRunner.class)
//Only need to declare the class calling the constructor to use
//PowerMockito.whenNew(). You do not need to declare the class whose mock
//you plan on returning in case of the constructor call.
//In this case, no need to mention MyClass.class in PrepareForTest
#PrepareForTest({ClassInstantiatingObject.class})
public class ClassInstantiatingObjectTest
{
.
.
.
#Test
public void testDoSomething() throws Exception {
MyClass mockObj = PowerMockito.mock(MyClass.class);
PowerMockito.whenNew(MyClass.class).withAnyArguments().thenReturn(mockObj);
//Only way to do nothing via Powermock for a local scope object
//whose method call returns void
//PowerMockito.doNothing().when(mockObj.loadContent(null,null));
//will cause a compile time exception
PowerMockito.doNothing().when(mockObj,"loadContent",null,null);
Arg1 mockArg1 = mock(Arg1.class);
Arg2 mockArg2 = mock(Arg2.class);
StaticClass.doSomething(mockArg1, mockArg2);
}
}
The ^above code will be the solution.
Related
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:
#RunWith(PowerMockRunner.class),
#PrepareForTest({Files.class}),
PowerMockito.mockStatic(Files.class),
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.
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");
I am trying to Mock constructor with no args in ResourceConfig.class.
It happens that ResourceConfig has two constructors: (among other ones):
public ResourceConfig()
public ResourceConfig(Class... class)
PowerMock (1.7.3) fails to get the right constructor.
I would consider this as a bug; but perhaps there is a solutoin to it(?)
Code:
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.whenNew;
#RunWith(PowerMockRunner.class)
#PrepareForTest( ResourceConfig.class )
public class StackOverflowTest {
#Test
public void toStackOvflow2() throws Exception {
ResourceConfig resConf = mock(ResourceConfig.class);
whenNew(ResourceConfig.class).withNoArguments().thenReturn(resConf);
//WHATEVER...
}
}
This produces:
org.powermock.reflect.exceptions.TooManyConstructorsFoundException:
Several matching constructors found, please specify the argument
parameter types so that PowerMock can determine which method you're
referring to. Matching constructors in class
org.glassfish.jersey.server.ResourceConfig were:
org.glassfish.jersey.server.ResourceConfig( )
org.glassfish.jersey.server.ResourceConfig( [Ljava.lang.Class;.class )
at
org.powermock.reflect.internal.ConstructorFinder.throwExceptionWhenMultipleConstructorMatchesFound(ConstructorFinder.java:89) ...
Any ideas?
You can suppress the multiple constructors, for example:
#Test
public void toStackOvflow2() throws Exception {
ResourceConfig resConf = mock(ResourceConfig.class);
// suppress TooManyConstructorsFoundException
MemberModifier.suppress(MemberMatcher.constructorsDeclaredIn(ResourceConfig.class));
whenNew(ResourceConfig.class).withNoArguments().thenReturn(resConf);
// verifying that the expected ResourceConfig instance is returned when using the default ctor ...
assertSame(resConf, new ResourceConfig());
}
This test passes with:
PowerMock 1.7.3
Jersey 2.26
Example for File class that can receive a String or an Uri:
whenNew(File.class).withParameterTypes(String.class).withArguments(any(String.class)).thenReturn(mockFile);
Best approach(if you know the String value in this case):
whenNew(File.class).withArguments(eq("SOME STRING")).thenReturn(mockFile);
I'm trying to test a class which uses a calculator class with a number of static methods. I've successfully mocked another class in a similar way, but this one is proving more stubborn.
It seems that if the mocked method contains a method call on one of the passed in arguments the static method is not mocked (and the test breaks). Removing the internal call is clearly not an option. Is there something obvious I'm missing here?
Here's a condensed version which behaves the same way...
public class SmallCalculator {
public static int getLength(String string){
int length = 0;
//length = string.length(); // Uncomment this line and the mocking no longer works...
return length;
}
}
And here's the test...
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.solveit.aps.transport.model.impl.SmallCalculator;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SmallCalculator.class})
public class SmallTester {
#Test
public void smallTest(){
PowerMockito.spy(SmallCalculator.class);
given(SmallCalculator.getLength(any(String.class))).willReturn(5);
assertEquals(5, SmallCalculator.getLength(""));
}
}
It seems there's some confusion about the question, so I've contrived a more 'realistic' example. This one adds a level of indirection, so that it doesn't appear that I'm testing the mocked method directly. The SmallCalculator class is unchanged:
public class BigCalculator {
public int getLength(){
int length = SmallCalculator.getLength("random string");
// ... other logic
return length;
}
public static void main(String... args){
new BigCalculator();
}
}
And here's the new test class...
import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.solveit.aps.transport.model.impl.BigCalculator;
import com.solveit.aps.transport.model.impl.SmallCalculator;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SmallCalculator.class})
public class BigTester {
#Test
public void bigTest(){
PowerMockito.spy(SmallCalculator.class);
given(SmallCalculator.getLength(any(String.class))).willReturn(5);
BigCalculator bigCalculator = new BigCalculator();
assertEquals(5, bigCalculator.getLength());
}
}
I've found the answer here https://blog.codecentric.de/en/2011/11/testing-and-mocking-of-static-methods-in-java/
Here's the final code which works. I've tested this approach in the original code (as well as the contrived example) and it works great. Simples...
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SmallCalculator.class})
public class BigTester {
#Test
public void bigTest(){
PowerMockito.mockStatic(SmallCalculator.class);
PowerMockito.when(SmallCalculator.getLength(any(String.class))).thenReturn(5);
BigCalculator bigCalculator = new BigCalculator();
assertEquals(5, bigCalculator.getLength());
}
}
First of all, remove that line:
given(SmallCalculator.getLength(any(String.class))).willReturn(5);
Since you are testing the same method. You don't want to mock the method that you're testing.
Secondly, modify your annotation to:
#PrepareForTest({ SmallCalculator.class, String.class})
Lastly, add the mock for the length(); like this:
given(String.length()).willReturn(5);
I think it will do ;)
Use anyString() instead of any(String.class).
When using any(String.class) the passed argument is null, as Mockito will return the default value for the reference type, which is null. As a result you get an exception.
When using the anyString(), the passed argument will be empty string.
Note, this explains why you get an exception, however you need to review the way you test your method, as explained in other comments and answers.
If you do not want that actual method being invoked. Instead of
when(myMethodcall()).thenReturn(myResult);
use
doReturn(myResult).when(myMethodCall());
It is mocking magic and it is difficult to explain why it is actually works.
Other thing you forgot is mockStatic(SmallCalculator.class)
And you do not need PowerMockito.spy(SmallCalculator.class);
I have the following sample unit test that tries to mock java.nio.file.Files but this mock does not work and the code attempts to delete the sample path.
#Test
public void testPostVisitDirectory() throws Exception {
Path mockedPath = Paths.get("sample path");
PowerMockito.mockStatic(Files.class);
PowerMockito.doNothing().when(Files.class,
PowerMockito.method(Files.class, "delete", Path.class));
DeleteDirVisitor visitor = new DeleteDirVisitor(false);
Assert.assertEquals("The was a problem visiting the file",
FileVisitResult.CONTINUE,
visitor.postVisitDirectory(mockedPath, null));
}
Any idea what is wrong?
this is the content of the method visitor.postVisitDirectory
[...]
if (e == null) {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
[...]
Thanks,
I had a similar problem using powermock 1.5.1 and the Files class and suspect it has a problem static mocking some/all jdk1.7 classes, although I don't know why. I also checked javassist version and at the time it was latest (3.18.0-GA),
I stripped my class under test to just the Files line and it still did not work. I then decided to try to mock another static class, StringUtils.chop("string"); (commons-lang3) and then my powermock test worked and I was able to force it to generate an exception from mock.
This proved to me that I'd done everything by the book and that static mocking didn't work on Files class but it did on StringUtils.
By the way I changed, both, the #PrepareForTest and the PowerMockito.mockStatic() calls to reference the correct class.
In the end I gave up mocking Files. Just a heads-up in case anyone else has the same problem.
EDIT. Got it working: I have since tried this again as I needed it in another project. There is a newer version of PowerMock out (1.5.3) which uses an updated javassist (3.18.1-GA) that fixes a bug I mentioned in my response to another comment.
I can consistently get mocking of Files to work by adding the class under test to #PrepareForTest as well as Files now even if the class you are testing does not expose static methods. I hadn't needed to do this before for other static mocking. I don't know why it's needed or works differently for Files.
Example:
public class MyTestClass {
public void justToTestMocking(Path path) throws IOException {
if (!Files.exists(path)) {
throw new IllegalArgumentException("I know there is a deleteIfExists() but I am just testing mocking");
}
Files.delete(path);
}
}
And the test below:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Files.class, MyTestClass.class})
public class MyTestClassTest {
#Before
public void setUp() {
mockStatic(Files.class);
}
#Test
public void justToTestMocking_WillDeletePath() throws IOException {
Path path = mock(Path.class);
MyTestClass test = new MyTestClass();
when(Files.exists(path)).thenReturn(true);
test.justToTestMocking(path);
verifyStatic();
Files.delete(path);
}
}
Did you add
#RunWith(PowerMockRunner.class)
#PrepareForTest(Files.class)
to your junit test class containing that method?
See powermock docs, the Writing tests section.
EDIT:
Hmmm, it seems like you're doing everything right. Here's what I'm running:
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Files.class)
public class TestVisitor {
public class PrintingVisitor extends SimpleFileVisitor<Path> {
#Override
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
}
#Test
public void testPostVisitDirectory() throws Exception {
final Path mockedPath = Paths.get("sample path");
/* Mocking */
PowerMockito.mockStatic(Files.class);
PowerMockito.doNothing().when(Files.class, PowerMockito.method(Files.class, "delete", Path.class));
/* End Mocking */
final PrintingVisitor visitor = new PrintingVisitor();
Assert.assertEquals("The was a problem visiting the file", FileVisitResult.CONTINUE, visitor.postVisitDirectory(mockedPath, null));
}
}
If I comment out the section labeled Mocking I get the NoSuchFileException. If I leave it, the test passes.
Perhaps post complete example which produces the error?
I had a similar issue and it turns out that it was related to preparing the correct classes.
In the example above the class that was tested was already in the "prepareFor-Scope" because it was an inner class of the test class.
You have to add the classes to #PrepareForTest that call the static methods ... and in my case these was not sufficient because the code that accessed Files.deletewas inside an anonymous class that cannot be explicitly prepared.
I named the anonymous class and added it to #PrepareForTest and everything worked
Can anyone make any suggestions about how best to use EasyMock to expect a call to Runtime.getRuntime().exec(xxx)?
I could move the call into a method in another class that implements an interface, but would rather not in an ideal world.
interface RuntimeWrapper {
ProcessWrapper execute(String command) throws IOException;
}
interface ProcessWrapper {
int waitFor() throws InterruptedException;
}
I was wondering if anyone had any other suggestions?
Your class shouldn't call Runtime.getRuntime(). it should expect a Runtime to be set as its dependency, and work with it. Then in your test you can easily provide a mock and set it as a dependency.
As a sidenote, I'd suggest watching this lecture on OO Design for testability.
Update: I didn't see the private constructor. You can try using java bytecode instrumentation in order to add another constructor or make the constructor public, but that might turn out to be impossible as well (if there are some restrictions on that class).
So your option is to make a wrapper (as you suggested in the question), and follow the dependency-injection approach.
Bozho above is IMO the Correct Solution. But it is not the only solution. You could use PowerMock or JMockIt.
Using PowerMock:
package playtest;
public class UsesRuntime {
public void run() throws Exception {
Runtime rt = Runtime.getRuntime();
rt.exec("notepad");
}
}
package playtest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.legacy.PowerMockRunner;
import static org.powermock.api.easymock.PowerMock.*;
import static org.easymock.EasyMock.expect;
#RunWith(PowerMockRunner.class)
#PrepareForTest( { UsesRuntime.class })
public class TestUsesRuntime {
#Test
public void test() throws Exception {
mockStatic(Runtime.class);
Runtime mockedRuntime = createMock(Runtime.class);
expect(Runtime.getRuntime()).andReturn(mockedRuntime);
expect(mockedRuntime.exec("notepad")).andReturn(null);
replay(Runtime.class, mockedRuntime);
UsesRuntime sut = new UsesRuntime();
sut.run();
}
}
Perhaps instead of mocking Runtime.getRuntime().exec() you could "mock" the script/program/etc. it's supposed to be calling.
Instead of passing the real command-line string into exec(), write a test script and execute it instead. You could have the script return hard-coded values you could test against just like a mocked class.
Here is how you would do it with EasyMock 3.0 (and JUnit 4):
import org.junit.*;
import org.easymock.*;
import static org.easymock.EasyMock.*;
public final class EasyMockTest extends EasyMockSupport
{
#Test
public void mockRuntimeExec() throws Exception
{
Runtime r = createNiceMock(Runtime.class);
expect(r.exec("command")).andReturn(null);
replayAll();
// In tested code:
r.exec("command");
verifyAll();
}
}
The only problem with the test above is that the Runtime object needs to be passed to code under test, which prevents it from using Runtime.getRuntime().
With JMockit, on the other hand, the following test can be written, avoiding that problem:
import org.junit.*;
import mockit.*;
public final class JMockitTest
{
#Test
public void mockRuntimeExec() throws Exception
{
final Runtime r = Runtime.getRuntime();
new NonStrictExpectations(r) {{ r.exec("command"); times = 1; }};
// In tested code:
Runtime.getRuntime().exec("command");
}
}