PowerMockito.verifyPrivate always working independently of parameters - java

As the title states, I can call verifyPrivate but it always gives me success even if I pass the wrong parameters to it.
Real example
#RunWith(PowerMockRunner.class)
#PrepareForTest({MyService.class})
public class MyServiceTest {
#InjectMocks
MyService service;
#Mock
OperationSivRepo operationSivRepo;
#Test
public void getNbInscriptions_should_call_getNbOperationsSiv_with_OPERATION_INSCRIPTION_GAGE() throws Exception {
// GIVEN
Role role = Role.ADMINISTRATEUR;
String operator = "operator";
SivDto sivDto = new SivDto();
// WHEN
service.getNbInscriptions(operator, role, sivDto);
// THEN
verifyPrivate(service).invoke("privateMethod", operator, Role.ADMINISTRATEUR, sivDto);
}
}
Now this code will succeed, even if I do something like
// THEN
verifyPrivate(service).invoke("privateMethod", "other string", Role.USER, new SivDto());
Maybe I'm missing something but I just can't figure it out.

Firstly. Did you put a debug point in privateMethod and see how many times it is getting called? This would have given you some hint.
It is getting called two times. Once when you call
service.getNbInscriptions(operator, role, sivDto);
and once when you use
verifyPrivate(service).invoke("privateMethod", operator, Role.ADMINISTRATEUR, sivDto);
Second time since it is getting called with the arguments you passed to invoke method, the tests always succeed.
Use Spy instead of Mock
Instead of
#InjectMocks
MyService service;
Use
#Spy
MyService myservice = new MyService(operationSivRepo)
Wiht this, second invocation to the method is not made and arguments are verified properly.

Related

About #InjectMocks and #Mock

I want to test requestListServiceImpl this class.It contains requestListDao.
RequestListServiceImpl Code
#Override
public PageInfo<RequestList> getAllRequest(int startPage, int pageSize, String accountName,String userName) {
PageHelper.startPage(startPage, pageSize);
List<RequestList> list=requestListDao.getAllRequest(accountName,userName);
for(RequestList requestList:list) {
switch (requestList.getStatus()) {
case "0":
requestList.setStatus("Waiting");
break;
case "1":
requestList.setStatus("Closed");
break;
case "2":
requestList.setStatus("Cancel");
break;
default:
requestList.setStatus("NAN");
break;
}
}
PageInfo<RequestList> pageInfo = new PageInfo<RequestList>(list);
return pageInfo;
}
#Override
public void createRequest(RequestList requestList) {
Integer coount=requestListDao.getTime(requestList.getCreateName());
// AWSSnsUtil.sendMassageToSns(requestList.getAccountName());
requestList.setTime(++coount);
requestListDao.createRequest(requestList);
}
Test Code:
#InjectMocks
RequestListServiceImpl requestListServiceImpl;
#Mock
RequestListDao requestListDao;
#Before
public void setup(){
MockitoAnnotations.openMocks(this);
}
#Test //it's ok
public void testGetAllRequest() throws Exception {
RequestList r=new RequestList();
r.setStatus("0");
when(requestListDao.getAllRequest(anyString(), anyString())).thenReturn(Arrays.<RequestList>asList(r));
PageInfo<RequestList> res=requestListServiceImpl.getAllRequest(1,1,"1","1");
Assert.assertNotNull(res);
}
#Test //this test is error, the error is requestListServiceImpl is not mock.
public void testCreateRequest() throws Exception {
when(requestListDao.getTime(anyString())).thenReturn(0);
RequestList r=new RequestList();
r.setCreateName("demo");
requestListServiceImpl.createRequest(r);
verify(requestListServiceImpl).createRequest(r);
}
Error info
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type RequestListServiceImpl and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
verify(mock).someMethod();
verify(mock, times(10)).someMethod();
verify(mock, atLeastOnce()).someMethod();
When i change #InjectMocks to #Mock, The second test it's ok ,but first test it's error.
I need add to a stubbing when(requestListServiceImpl.getAllRequest(anyInt(),anyInt(),anyString(),anyString())).thenReturn(new PageInfo<>());
I don't know how to do it,
Is injectmocks necessary?
Here:
verify(requestListServiceImpl)
And
#InjectMocks
RequestListServiceImpl requestListServiceImpl;
The message is pretty clear: you verify mock objects that Mockito created for you.
#InjectMocks does not create mocks. It rather injects mocks that you have in your test class into a real object.
So, what is necessary here: read the manual or a tutorial. Meaning: don't start with Mockito by applying it immediately to your project. Instead, step back, and look at simple examples to understand how it is supposed to be used.
In your current setup: requestListServiceImpl is a real object. So you should check if that class offers you methods to verify its internal status. You triggered some action on it, but because it is a real object, Mockito doesn't know what you did. But how to actually solve this depends on YOUR code base.
You want to test requestListServiceImpl you should use #InjectMocks so mockito calls the real method on requestListServiceImpl. When you use #Mock, the method will by default not be invoked.
#InjectMocks will be the same as if you create it yourself with new requestListServiceImpl(mock(requestListDao))
When you use verify(mock).someMethod(); you have to pass a mock to that method, not #InjectMocks.
You want to verify if a certain method is called on a mock inside your class under test(requestListServiceImpl).
Instead of #InjectMocks there is also #Spy, which will kinda do both, you can mock methods in requestListServiceImpl but also call the real method.

How to test a utility method that returns a new instance using Jupiter in Java?

I have a something like this one:
class User {
String name;
}
class Contacts {
User getUser() {
return new User();
}
}
I do it this way so that in my test I can mock the method like:
#ExtendWith(MockitoExtension.class)
class ContactsTest {
#Spy
private Contacts sut;
#Mock
private User user;
#Test
void testSomething() {
doReturn(user).when(sut).getUser();
}
#Test
void testGetUser() {
// verify(new User(), times(1));
// verify(user, times(1));
}
}
How could I test testGetUser?
The only two ideas I had which are commented above gave me these errors:
For the first one:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type User and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
verify(mock).someMethod();
verify(mock, times(10)).someMethod();
verify(mock, atLeastOnce()).someMethod();
For the second one
org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
First of all, since your unit under test is the Contacts class there is no need to spy on it and mock its behavior as this is the class you need to test. So, I would go ahead and remove that.
Now regarding your question, what you need to test is the actual outcome of the getUser, so the simplest of all tests would be to invoke the method on an instance of Contacts and assert that the returned result is a non-null instance of a User object.
If you really want to test that the constructor of the User class gets called, you will need to actually mock that call using either PowerMock (which is advise against and most likely does not even work with JUnit5) or use mockito-inline.
Once this is done you would be able to return a mocked User instance from the constructor call which you can then run assertions on.

Getting NullPointerException while calling nested method of Service class using mockito

I am writing JUnit test cases for my Service classes.
I have created dummy data to understand my scenario.
#Service
MainClass {
#Autowired
C c;
public void someServiceMethod(){
ResultClass someResult = c.getResult(string,string, int, int, List<String>,boolean);
}
}
#Service
public class C {
#Autowired
SomeRepository someRepository;
public ResultClass getResult(string,string, int, int, List<String>,boolean){
ABC returnSomeClassObject = someRepository.getSomeData(String,int,int);
}
}
#Test
MainClassTest {
#MockBean
SomeRepository someRepository;
when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(SomeRepository);
//calling MainClass method
MainClass.someServiceMethod();
}
Class C's getSomeData() method returning ABC class object which is NULL and latter setting into another same class type object.
After setting value I am getting NULLPointerException as ABC is NULL.
Anybody have any idea where I am going wrong?
You are not returning expected object while writing mock statement
#Service
public class C {
#Autowired
SomeRepository someRepository;
public ResultClass getResult(string,string, int, int, List<String>,boolean){
ABC returnSomeClassObject = someRepository.getSomeData(String,int,int);
//Your return type should be ResultClass
// Where your return statement
// What is ABC?
}
}
#Test
MainClassTest {
#MockBean
SomeRepository someRepository;
when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(SomeRepository);
// Why are you returning SomeRepository, This Should return object of ABC
#MockBean
ABC mockResultClass
when(someRepository.getSomeData(anyString(),anyInt(),anyInt())).thenReturn(mockResultClass);
//calling MainClass method
MainClass.someServiceMethod();
}
You are calling MainClass.someServiceMethod() which in turn calls getResult of class C. You should be mocking class C and using when-thenReturn on getResult() of C class if your intention is to test someServiceMethod() of Main class. Autowired will not work here since this is a Unit test and hence the instance of C c in Main class will be null.
Something like below:
#MockBean
C c;
when(c.getResult(anyString(), anyString(),anyInt(),anyInt(), any(List.class), anyBoolean()).thenReturn(someResult);
c.getResult(string,string, int, int, List<String>,boolean);
So, first of all, we need to be clear on what exactly you are unit testing. If you are trying to unit test someServiceMethod inside of MainClass, then that means you should NOT be also testing the functionality of someRepository. The idea is that each unit test should only be testing just that, a unit of code. So, to do that we need to use stubs as stand-ins for what would actually happen when you call methods owned by other classes. Then, we would write a differrent unit test just for someRepository.getSomeData() to confirm that it is also working as intended. In this manner, when get an error later down the line we will know exactly where we are encountering an issue.
Another issue I see is there is an apparent mismatch of return types for getResult() in C. The method says it returns a ResultClass, but when you call getSomeData you are expecting an ABC object. Either you left out the details where you convert the object back to a ResultClass, or that is a mistake. I'm going to assume the former unless you say otherwise.
With that in mind, let's write our test. Here's how I would write the test:
#RunWith(SpringRunner.class)
public class MainClassTest {
#Mock
C c;
#InjectMocks
MainClass mainClass;
#Test
public void testSomeServiceMethod {
ResultClass resultClass = new ResultClass(); //relevant constructor details here, mockbean, etc. you get the idea
//set any desired data for resultClass here
Mockito.when(c.getResult(anyString(), anyString(),
anyInt(), anyInt(), any(List.class), anyBoolean()))
.thenReturn(resultClass);
ResultClass newResult = mainClass.someServiceMethod();
//relevant test assertions here
}
}
As you can see, we are creating a ResultClass in the test, and telling Mockito to return that when getResult is called instead of what you would normally expect it to return. While the functionality may seem limited now, this is preferred as we only testing the MainClass and not the rest of our method calls.
In addition to this, we can (and should) write tests for getResult in C, and getSomeData in SomeRepository. I will leave it to you to write those tests.
EDIT: accidentally posted a bit early, fixing now.

Mocking not able to mock method call

I am trying to mock a call in my test but I am getting a error as its calling the real method than mocking it.
This is my method
#Value("${omega.aws.nonprod-profile}")
private String nonProdProfile;
#Autowired
AwsService awsService;
public List<SecurityGroup> getAllSecurityGroups() {
AmazonEC2 ec2 = configSetter();
return awsService.getAllSecurityGroups(ec2);
}
protected AmazonEC2 configSetter() {
ProfileCredentialsProvider credentials = new ProfileCredentialsProvider(nonProdProfile);
ClientConfiguration clientCfg = new ClientConfiguration();
clientCfg.setProxyHost(this.proxyHost);
clientCfg.setProxyPort(Integer.valueOf(proxyPort));
clientCfg.setProtocol(Protocol.HTTPS);
return new AmazonEC2Client(credentials, clientCfg);
}
Here is my test class
#InjectMocks
private AwsConfigurationLocal subject;
#Mock
private AwsService awsService;
#Test
public void TestgetAllSecurityGroups() throws Exception {
ec2 = Mockito.mock(AmazonEC2Client.class);
securityGroup = new SecurityGroup();
List<SecurityGroup> result = Collections.singletonList(securityGroup);
Mockito.when(awsService.getAllSecurityGroups(ec2)).thenReturn(result);
List<SecurityGroup> actual = subject.getAllSecurityGroups();
assertThat(actual, CoreMatchers.is(equals(result)));
}
The test actually calls the protected method configSetter and fails when setting a proxy. Help me understand what I am doing wrong here.
subject.getAllSecurityGroups(); calls real configSetter() which returns real AmazonEC2 which in turn is passed on to awsService.getAllSecurityGroups(ec2);. The parameter doesn't match your mock ec2 so the default mock implementation is returned (I guess it's null) as a actual.
So the issue is: there is nothing that would prevent real implementation of configSetter() to be called.
If you annotate subject with #Spy and do
Mockito.when(subject.configSetter()).then(ec2);
it should work as expected.
That being said there's a lot of set up done only to check simple invocation being delegated. This is due intermixing of two responsibility in AwsConfigurationLocal - creation of AmazonEC2Client and providing getAllSecurityGroups(). If you move the former into separate class (let's say AmazonEC2ClientFactor) everything should fall in place.
Try using powerMockito to return the mocked instance of AmazonEC2
#RunWith(PowerMockRunner.class)
#PrepareForTest({AwsConfigurationLocal.class})//assuming this is your test class
#InjectMocks
private AwsConfigurationLocal subject=PowerMockito.spy(AwsConfigurationLocal.class);//or try Mockito.spy instead, whichever works
#Test
public void TestgetAllSecurityGroups() throws Exception {
ec2 = Mockito.mock(AmazonEC2Client.class);
PowerMockito.doReturn(ec2).when(subject).configSetter().withNoArguments();
//your code
}

Mock method as parameter another method

I have got a problem with testing how many times concrete methods (IFunction in the Operation instance) is invoked.
According to:
http://easymock.org/user-guide.html#mocking-annotations
http://www.ibm.com/developerworks/library/j-easymock/
How to use EasyMock expect
I wrote something as:
class Operation{
public double[] calculateSth(IFunction function, int [] t){
for(int i=0 ; i<5 ; i+=1)
function(t, new int[]{1,2,3});
return new double[]{1,2,3};
}
}
interface IFunction{
double f(int[] a, int[]b);
}
class ConcreteF implements IFunction{
double f(int[]a, int[]b){
return 5;
}
}
And my test class:
#TestSubject
Operation op;
#Mock
IFunction function;
#Before
public void setUp() throws Sth{
op=new Operation();
function = EasyMock.createMock(IFunction.class);
}
#Test
public void howManyTimes(){
EasyMock.expect(function.f(EasyMock.notNull(), EasyMock.notNull())
)
.andReturn((double)EasyMock.anyDouble()).times(3);
EasyMock.replay(function);
op.calculateSth(function, new double[]{0,0,0});
//verify
EasyMock.verify(function);
}
Result:
java.lang.NullPointerException
at org.easymock.internal.Injector.injectMocks(Injector.java:80)
at org.easymock.EasyMockSupport.injectMocks(EasyMockSupport.java:624)
at org.easymock.EasyMockRunner.withBefores(EasyMockRunner.java:50)
It's my first time using easymock and i don't know how to fix it ;/
I'll answer this question without going into the details of whether the original method does anything useful (the code doesn't even compile anyway), let alone the test method.
#TestSubject Operation op;
This line is a suspect. I realize that you are instantiating it in the #Before annotated setUp method, but it looks like the Easymock tries to inject the mocks (the ones annotated with #Mock) before it does anything (and understandably so) and blows up since the reference is null at that point.
The annotation support introduced in v3.2 is also seen as a way to eliminate the need for setUp method. But you seem to be mixing both and using it wrongly. Choose one or the other - I'd recommend you to use the annotations.
Quoting the Easymock user guide (this user guide is as good as it can ever be, so be sure read this up before using the library),
#RunWith(EasyMockRunner.class)
public class ExampleTest {
#TestSubject
private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2
#Mock
private Collaborator mock; // 1
#Test
public void testRemoveNonExistingDocument() {
replay(mock);
classUnderTest.removeDocument("Does not exist");
}
}
The mock is instantiated by the runner at step 1. It is then set by
the runner, to the listener field on step 2. The setUp method can be
removed since all the initialization was done by the runner.

Categories

Resources