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);
Related
I have a test to verify the return of a null object if a string property of that object does not match a pre-determined value. My code is
import guru.springframework.sfgpetclinic.model.Speciality;
import guru.springframework.sfgpetclinic.repositories.SpecialtyRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.BDDMockito.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
#ExtendWith(MockitoExtension.class)
class SpecialtySDJpaServiceTest {
#Mock
SpecialtyRepository specialtyRepository;
#InjectMocks
SpecialtySDJpaService service;
#Test
void testSaveLambdaNoMatch() {
// Given
final String MATCH_ME = "MATCH_ME";
Speciality speciality = new Speciality();
speciality.setDescription("Not a match");
Speciality savedSpeciality = new Speciality();
savedSpeciality.setId(1L);
// Need mock to only return on match MATCH_ME string
given(specialtyRepository.save(argThat(argument -> argument.getDescription().equals(MATCH_ME)))).willReturn(savedSpeciality);
// When
Speciality returnedSpeciality = service.save(speciality);
// Then
assertNull(returnedSpeciality);
}
// Other tests...
}
This test fails with the message
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'save' method:
specialtyRepository.save(
guru.springframework.sfgpetclinic.model.Speciality#19ae6bb
I believe the issue is that argThat() uses an exact matching scheme. I want to set the mock matching to lenient via
#Mock(lenient = true)
SpecialtyRepository specialtyRepository
But Intellij does not recognize the lenient parameter. I'm using JUnit 5 and Mockito 2.23.0
#Mock(lenient = true) was introduced in Mockito version 2.23.3.
You either have to upgrade or use the other way to write this:
lenient().when(specialtyRepository.save(argThat(argument -> argument.getDescription().equals(MATCH_ME)))).willReturn(savedSpeciality);
I just written sample test case, where I would like to mock a void instance method. I am surprised, my test case is passing without calling the expectLastCall method. I would like to know, is calling of expectLastCall is not required while mocking instance void methods?
StringUtil.java
package com.sample.util;
import com.sample.model.MethodNotImplementedException;
public class StringUtil {
public String toUpperAndRepeatStringTwice(String str) {
String upperCase = str.toUpperCase();
sendStringToLogger(upperCase);
return upperCase + upperCase;
}
public void sendStringToLogger(String str){
throw new MethodNotImplementedException();
}
}
StringUtilTest.java
package com.sample.util;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ StringUtil.class })
public class StringUtilTest {
#Test
public void toUpperAndRepeatStringTwice() {
StringUtil stringUtil = PowerMock.createPartialMock(StringUtil.class, "sendStringToLogger");
String str = "HELLO PTR";
stringUtil.sendStringToLogger(str);
//PowerMock.expectLastCall().times(1);
PowerMock.replayAll();
String result = stringUtil.toUpperAndRepeatStringTwice("hello ptr");
assertEquals(result, "HELLO PTRHELLO PTR");
}
}
expectLastCall is not required. For EasyMock and the PowerMock layer as well. So you are right.
It is used for clarity for some users. Because it makes it obvious that the method before is an expectation not some random call. But it is more a question of style than a requirement.
You also don't need the time(1) since it is the default.
BTW, the answer here is wrong and I've commented on it accordingly.
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.
I am new to JUnit.
I just started working on JUnit and i am getting following error.
The method assertEquals(String, String) is undefined for the type TestJunit
and my Javacode:
import org.junit.Test;
import static org.junit.Assert.assertArrayEquals;
public class TestJunit {
String message = "Hello World";
MessageUtil messageutil = new MessageUtil(message);
public void testPrintMessage()
{
assertEquals(message,messageutil.printMessage());
}
}
please help me resolve this issue.
You imported
import static org.junit.Assert.assertArrayEquals;
but not
import static org.junit.Assert.assertEquals;
You could also import every static member of Assert with
import static org.junit.Assert.*;
Without these, Java thinks you are calling the method assertEquals defined in the class the code is declared in. Such a method does not exist.
if importing doesn't work try saving before you run the code
PowerMock provides the method expectPrivate to mock out private methods, however it appears only in EasyMock api and not the Mockito API.
So, is there an equivalent for PowerMockito? I'm guessing not because I haven't found it and because of this wiki entry. but that doesn't actually prevent PowerMockito from working around it. So, I'm asking this mostly for confirmation and since I think this will be of value for others.
PowerMockito provides ways to mock private methods as well, from the API:
<T> WithOrWithoutExpectedArguments<T> when(Object instance, Method method)
Expect calls to private methods.
verifyPrivate(Object object, org.mockito.verification.VerificationMode verificationMode)
Verify a private method invocation with a given verification mode.
There are a bunch of other signatures of the type described above.
An example:
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 static org.mockito.Matchers.eq;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Foo.class)
public class SimpleTest {
#Test
public void testHello() throws Exception {
Foo foo = PowerMockito.spy(new Foo());
foo.sayHello();
PowerMockito.verifyPrivate(foo).invoke("hello", eq("User"));
}
}
class Foo {
public void sayHello() {
System.out.println(hello("User"));
}
private String hello(String user) {
return "Hello " + user;
}
}