Invoking a private method via JMockit to test result - java

Am using JMockit 1.1 and all I want to do is invoke a private method and test the return value. However, I am having trouble understanding exactly how to do this from the JMockit De-Encapsulation example.
The method I am trying to test is the private method in this class:
public class StringToTransaction {
private List<String> parseTransactionString(final String input) {
// .. processing
return resultList;
}
}
And my test code is below.
#Test
public void testParsingForCommas() {
final StringToTransaction tested = new StringToTransaction();
final List<String> expected = new ArrayList<String>();
// Add expected strings list here..
new Expectations() {
{
invoke(tested, "parseTransactionString", "blah blah");
returns(expected);
}
};
}
And the error I am getting is:
java.lang.IllegalStateException: Missing invocation to mocked type at
this point; please make sure such invocations appear only after the
declaration of a suitable mock field or parameter
Perhaps I have misunderstood the whole API here, because I don't think I want to mock the class.. just test the result of calling the private method.

I think you are making this too complicated. You should not be using the Expectations block at all. All you need to do is something like this:
#Test
public void testParsingForCommas() {
StringToTransaction tested = new StringToTransaction();
List<String> expected = new ArrayList<String>();
// Add expected strings list here..
List<String> actual = Deencapsulation.invoke(tested, "parseTransactionString", "blah blah");
assertEquals(expected, actual);
}
Basically, call a private method via Deencapsulation and test that the actual is equal to the expected. Just like you would if the method were public. No mocking is being done, so no Expectations block is needed.

At this point, I don't know if JMockit can or should be used for this. Testing my private method can be done with plain old reflection, although I started this exercise to learn about JMockit (and test my code). In case JMockit cannot be used for this, here is how I can use reflection instead.
#Test
public void testParsingForCommas() throws Exception {
StringToTransaction tested = new StringToTransaction();
ArrayList<String> expected = new ArrayList<>();
expected.add("Test");
Method declaredMethod =
tested.getClass().getDeclaredMethod("parseTransactionString",
String.class);
declaredMethod.setAccessible(true);
Object actual = declaredMethod.invoke(tested, "blah blah");
assertEquals(expected, actual);
}
The call to setAccessible(true) is important here or the invoke will blow up when calling a private method.
declaredMethod.setAccessible(true);
But you want to know what is really cool? If you don't call setAccessible(true), it will blow up with a java.lang.StackOverflowError! :)

As mocking private methods is not allowed in latest Jmockit. One can mock the APIs used inside that private method as a Workaround instead of mocking the private method.
This workaround can also be treated as a final solution.
Example:
Actual Class:
class A {
private int getId(String name){ //private method
return DAOManager.getDao().getId(name); //Call to non-private method can be mocked.
}
}
Test Class:
public class ATest{
#Before
public void setUp(){
new MockDAOManager();
}
//Mock APIs used by the private method `getId`.
public static class MockDAOManager extends MockUp<MockDAOManager>{
static mocked_user_id = 101;
#Mock
public DAOManager getDao() throws Exception{
return new DAOManager();
}
#Mock
public Integer getId(String name){
return mocked_user_id;
}
}
}
Note:
If you don't have such logic(private method calls to another non-private
method) then you may have to refactor your code, Otherwise this will
not work.
Here DAOManager.getDao().getId(name) is not a private API.
There may be a need to mock all APIs used by that private method.

start from 1.35(?) jmockit removed that helper method. for reasons that it is no longer useful (which I don't quite understand)
but yes, this utility is available somewhere else
org.springframework.test.util.ReflectionTestUtils

As mentioned by #Jeff Olson, you can also call the private methods of a bean by declaring them #Tested.
Here is an example:
// Java
#Tested
private YourServiceImplClass serviceImpl;
#Test
public void testPrivateMethod() {
List<String> expected = new ArrayList<String>();
// Add expected strings list here..
List<String> actual = Deencapsulation.invoke(serviceImpl, "yourPrivateMethod", "arguments");
assertEquals(expected, actual);
}

Why do you want to test the private method directly ? Most of the times API methods i.e. public interface methods are unit tested as private methods will be be indirectly tested as well along with them. You can put assert statements with expected values from private methods where you call them within the public methods. So if assert fails you are sure that there is some issue with the private method. So you need not test it separately.

Related

How to mock a static method in side a public class using Power mockito?

Hi every one I am trying to mock a static method name mapCreditInfo(UCIPin, creditAssessmentResults) which has two parameters UCIPin and creditAssessmentResults. UCIPin is String type and creditAssessmentResults is List
This method is inside a public class ResponseMapper
type as shown below:
private CreditInfo getAccountByUCI(String audiUser, String UCIPin) throws EnterpriseCustomerVerificationException {
List<CreditAssessmentResult> creditAssessmentResults = creditInfoRepository.getUCISummary(UCIPin, audiUser);
return ResponseMapper.mapCreditInfo(UCIPin, creditAssessmentResults);
}
Note: getAccountbyUCI method is called inside another public method
name executeCustomerVerification which is in the class
EnterpriseCustomerVerificationService
ResponseMapper class
public class ResponseMapper {
public static CreditInfo mapCreditInfo(String UCIPin, List<CreditAssessmentResult> creditAssessmentResults) {
CreditInfo creditInfo = new CreditInfo();
creditInfo.setUCIPin(UCIPin);
List<AccountCreditInfo> accountCreditInfos = new ArrayList<AccountCreditInfo>();
for (CreditAssessmentResult creditAssessmentResult : creditAssessmentResults) {
AccountCreditInfo accountCreditInfo = new AccountCreditInfo();
accountCreditInfo.setDelinquenctBalance(creditAssessmentResult.getPastDueAmount());
accountCreditInfo.setNonPayDisconnect(creditAssessmentResult.getNonpayDiscount());
accountCreditInfo.setPreviousAccountNumber(creditAssessmentResult.getAccountNumber());
accountCreditInfo.setUnreturnedEquipmentFlag(creditAssessmentResult.getUnreturnedEquipment());
accountCreditInfos.add(accountCreditInfo);
}
creditInfo.setAccountCreditInfo(accountCreditInfos);
return creditInfo;
}
}
I have Tried like some portion of my test class as shown below :
Test Class
#PrepareForTest( EnterpriseCustomerVerificationService.class)
#RunWith(PowerMockRunner.class)
public class EnterpriseCustomerVerificationServiceTest {
#InjectMocks
private EnterpriseCustomerVerificationService enterpriseCustormerVerificationServiceMock ;
#Test
public void executeCustomerVerificationTest() throws Exception {
List<ErrorResponse> errorResponses = getErrorResponse();
List<String> mso = new ArrayList<String>();
mso.add("a");
mso.add("b");
mso.add("c");
AddressResponse addressResponse = getAddressResponse();
String experianAuthorization = "experianAuthorization";
String UCIPin = "110019";
String auditUser = "ABC";
CreditInfo credit = getCreditInfo();
CreditCheck creditCheck = getcreditCheck();
EnterpriseCustomerVerificationService spy = PowerMockito.spy(new EnterpriseCustomerVerificationService());
PowerMockito.when(spy,PowerMockito.method(EnterpriseCustomerVerificationService.class,"executeCreditCheck",CreditCheck.class)).withArguments(Mockito.any()).thenReturn("#1");
Mockito.when(creditInfoRepository.getUCISummary("110019", "test")).thenReturn(getCreditAssessmentResultList());
PowerMockito.mockStatic(ResponseMapper.class);
Mockito.when(ResponseMapper.mapCreditInfo(UCIPin, getCreditAssessmentResultList())).thenReturn(credit);
CustomerVerification cv = spy
.executeCustomerVerification(getCustomerVerificationRequest1(),
"101");
}
My question is how to mock static mapCreditInfo method using power Mockito ?
Thanks
Like this ...
#RunWith(PowerMockRunner.class)
#PrepareForTest({ResponseMapper.class})
public class ATest {
#Test
public void testMockingStatic() {
PowerMockito.mockStatic(ResponseMapper.class);
// if you want to use specific argument matchers
Mockito.when(ResponseMapper.mapCreditInfo(
uciPin, creditAssessmentResults)
).thenReturn(creditInfo);
// or if you want to match on any arguments passed into your static method ...
Mockito.when(ResponseMapper.mapCreditInfo(
ArgumentMatchers.anyString(),
ArgumentMatchers.anyList())
).thenReturn(creditInfo);
// ...
}
}
Notes:
#PrepareForTest prepares the class with the static methods which you want to mock
PowerMockito.mockStatic mocks all static methods that class
You can use standard Mockito when/then constructs to tell the mocked static methods what to return
The example above uses these dependencies:
org.mockito:mockito-core:2.7.19
org.powermock:powermock-module-junit4:1.7.0
org.powermock:powermock-api-mockito2:1.7.0
Update 1: based on your updated question which shows your test method ...
My example includes: #PrepareForTest({ResponseMapper.class}) your test method is not preparing ResponseMapper instead it is preparing EnterpriseCustomerVerificationService. It's like you are preparing the class which calls the class which has a static method rather than preparing the class which contains the static method.
I would strongly suggest creating a new test case - just temporarily - which looks like the one I have provided and use that to show yourself how to mock a static method and once you are comfortable with that then work that into your EnterpriseCustomerVerificationServiceTest.
Is it possible to change the source code? if so maybe you could try to solve the problem without using any mocking framework at all.
see my comment on How To Java Unit Test a Complex Class

Mockito: using a method in "thenReturn" to return a mock doesn't work

I have encountered what I assume might be a bug with Mockito, but was wondering if anyone else can shed light as to why this test doesn't work.
Basically, I have two objects, like this:
public class FirstObject {
private SecondObject secondObject;
public SecondObject getSecondObject() { return secondObject; }
}
public class SecondObject {
private String name;
public String getName() { return name; }
}
The first object is mocked via annotation and the before method:
#Mock
FirstObject mockedFirstObject;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
The second object is mocked in a method:
public SecondObject setupMockedSecondObject() {
SecondObject secondObject = Mockito.mock(SecondObject.class);
Mockito.when(secondObject.getName()).thenReturn("MockObject");
return secondObject;
}
When thenReturn contains a direct call to this method to setup and obtain a mock of the second object, it fails:
#Test
public void notWorkingTest() {
Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(setupMockedSecondObject());
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
But, when the mock returned by the same method is assigned to a local variable, which is used in thenReturn, it works:
#Test
public void workingTest() {
SecondObject mockedSecondObject = setupMockedSecondObject();
Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(mockedSecondObject);
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
Are we doing something wrong or is this indeed a bug/limitation in Mockito? Is there a deliberate reason for this not working?
This is indeed a limitation of Mockito, and it is referenced in their FAQ:
Can I thenReturn() an inlined mock()?
Unfortunately you cannot do this:
when(m.foo()).thenReturn(mock(Foo.class));
// ^
The reason is that detecting unfinished stubbing wouldn't work if we allow above construct. We consider is as a 'trade off' of framework validation (see also previous FAQ entry). However you can slightly change the code to make it working:
//extract local variable and start smiling:
Foo foo = mock(Foo.class);
when(m.foo()).thenReturn(foo);
The workaround, as mentioned, is to store the desired returned value in a local variable, like you have done.
The way I understand it is that Mockito validates the usage you make of it every time you call its methods. When another method is called during an on-going stubbing process, you are breaking its validation process.
You can't use a method in thenReturn, but you can in thenAnswer
Your code will be called after the when condition will occur,
unlike any workaround based on thenReturn
Thus you could write:
#Test
public void nowWorkingTest() {
Mockito.when(mockedFirstObject.getSecondObject()).thenAnswer(new Answer<Map>() {
#Override
public Map answer(InvocationOnMock invocation) {
return setupMockedSecondObject();
}
});
Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}
Let find another example here
#Test
public void testAuthenticate_ValidCredentials() throws FailedToAuthenticateException {
String username = "User1";
String password = "Password";
/*Configure Returning True with when...thenReturn configuration on mock Object - Q5*/
//Write your code here
assertTrue(authenticator.authenticateUser(username, password));
}

How to mock Session object in java

I have created a method, in which i am using JaloSession. I am writing a Junit test for this.
Please let me know how can i mock the following.
ABC abc = JaloSession.getCurrentSession.getAttribute("abc");
Thanks in advance.
With powermock you can mock the static call:
mockStatic(JaloSession.class);
expect(JaloSession.getCurrentSession()).andReturn(yourMock);
...etc
However you don't need to do that. Perhaps the easiest thing since you control the code is to wrap this method call in a protected method
protected ABC getAbc(){
return JaloSession.getCurrentSession.getAttribute("abc");
}
And then in your tests, make a subclass of your class that overrides getAbc() to return a different ABC instance.
#Test
public void myTest(){
final ABC mockAbc = ....
Foo foo = new Foo(){
#Override
protected ABC getAbc(){
return mockAbc;
}
};
//do test on Foo
}
You can't (easily) because of the static call.
So either pass the current session in to the function you are testing, or define an interface for getting the current session and pass that to your object's constructor. In production implement it to call the static nmethod, and in test either mock it or build a fake.
As a bonus you will end up with a cleaner design, where dependencies are passed in from above instead of directly accessed at the lowest levels.
With the JMockit mocking library, you can mock it as follows:
#Test
public void mockJaloSession(#Mocked final JaloSession jalo) {
final ABC testABC = new ABC();
new Expectations() {{ jalo.getAttribute("abc"); result = testABC; }};
// From code under test:
ABC abc = JaloSession.getCurrentSession().getAttribute("abc");
assertSame(testABC, abc);
}
(The test doesn't need to worry about the getCurrentSession() call as it will automatically return the mock jalo object.)

Mockito ArgumentMatcher saying Arguments are Different

I am using Mockito for Unit testing and I am using ArgumentMatcher to check if a particular field of an argument has a particular value.
I have a StatusMatcher class that extends ArgumentMatcher and checks whether an object of class MyClass has a particular value in status field. The way I am invoking this in the tests is:
verify(myDAO, times(1)).update(argThat(new StatusMatcher("SomeStatus")));
Here update is the method of the DAO that is getting called with some MyClass object. I want to see if it has the correct status or not. This is what I get:
Argument(s) are different! Wanted:
myDAO.update(
<Status matcher>
);
-> at com.foo.bar.MyTest.test1
Actual invocation has different arguments:
myDAO.update(
com.foo.bar.MyClass
);
Note that this is working perfectly for all the test cases except one test case. So I know the StatusMatcher etc. have been coded correctly. I am not sure what is different about the method where its getting this exception.
What I want to know is: under what conditions will the ArgumentMatcher throw such exception so I can find out what I am missing (It is not for me to paste the actual method codes)
Please tell me if the explanation is not clear enough, and I will try to improve it. Thanks for reading this far :)
EDIT: Here is the code for my StatusMatcher class
private class StatusMatcher extends ArgumentMatcher<MyClass> {
private String status;
public StatusMatcher(String hs) {
status = hs;
}
#Override
public boolean matches(Object argument) {
return status.equals(((MyClass)argument).getStatus());
}
}
Like you said, it fails because the arguments are different. Take a look at the test below and you'll see that the second test method will fail because the status in your MyClass instance is different from SomeStatus that you passed in the matcher.
public class MatcherTest {
class MyClass{
private String status;
MyClass(String status) {
this.status = status;
}
public String getStatus(){
return status;
}
}
class MyDao {
public void update(MyClass myClass){}
}
class StatusMatcher extends ArgumentMatcher<MyClass> {
private String status;
public StatusMatcher(String hs) {
status = hs;
}
#Override
public boolean matches(Object argument) {
return status.equals(((MyClass)argument).getStatus());
}
}
#Test
public void shouldMatchStatus(){
MyDao mock = mock(MyDao.class);
mock.update(new MyClass("expectedStatus"));
verify(mock, times(1)).update(argThat(new StatusMatcher("expectedStatus")));
}
#Test
public void shouldNotMatchStatus(){
MyDao mock = mock(MyDao.class);
mock.update(new MyClass("unexpectedStatus"));
/* THE BELLOW WILL FAIL BECAUSE ARGUMENTS ARE DIFFERENT */
verify(mock, times(1)).update(argThat(new StatusMatcher("expectedStatus")));
}
}
I could take a wild guess that you could be reusing variables, or have a static field, etc. But without seeing your test code, no one can tell.
Try to simplify the test / code under test. Do you really need to
mutate arguments and also verify stubbing? Both of those actions
might indicate a code smell. Relax the argument verification and
use some kind of any() matcher Perform validation of arguments in the
For others that are facing a similar issue here is how I fixed it.
The code below will throw the following error if you pass in a new instance of an object. All you have to do in this case is create a variable since it will not create a new reference in memory.
#Test
void shouldLogExceptionWithType() {
mongoDao = mock(MongoDao.class);
StepDetail stepDetail = StepDetail.builder()
.table("some table")
.batchType("Some batch type")
.build();
doCallRealMethod().when(mongoDao).logException(new Exception(), stepDetail.getBatchType().getName());
mongoDao.logException(new Exception(), stepDetail.getBatchType().getName());
verify(mongoDao, times(1)).logException(new Exception(), stepDetail.getBatchType().getName());
}
Code Fixed:
#Test
void shouldLogExceptionWithType() {
mongoDao = mock(MongoDao.class);
StepDetail stepDetail = StepDetail.builder()
.table("some table")
.batchType("Some batch type")
.build();
Exception exception = new Exception();
doCallRealMethod().when(mongoDao).logException(exception, stepDetail.getBatchType().getName());
mongoDao.logException(exception, stepDetail.getBatchType().getName());
verify(mongoDao, times(1)).logException(exception, stepDetail.getBatchType().getName());
}
I also faced this issue. Below is the error and its solution:
error: Argument(s) are different! Wanted:
tradeMaintenanceDao.updateTradesMaintData(.....
I used the following statement to resolve it:
verify(tradeMaintenanceDao, times(1))
.updateTradesMaintData(anyString(), anyList(), anyList(), anyString(), anyString());
The original cause was:
verify(tradeMaintenanceDao, times(1)).updateTradesMaintData(userName, tradeStatusList, tradeReasonList, notes, pendStatus);

Mockito bypass static method for testing

I need to test handleIn() method using Mockito.
However the code need to call this legacy code Util.getContextPDO which is a static method.
Note that in testing environment this Util.getContextPDO is always returns Exception, and I intend to bypass this Util.getContextPDO() by always return a dummy IPDO.
public class MyClass {
public IPDO getIPDO()
{
return Util.getContextPDO(); // note that Util.getContextPDO() is a static, not mockable.
}
public String handleIn(Object input) throws Throwable
{
String result = "";
IPDO pdo = getIPDO();
// some important business logic.
return result;
}
}
Initially I thought this achieveable by using spy() of the class "MyClass", so I can mock the return value of getIPDO(). Below is my initial effort using spy ()
#Test
public void testHandleIn() throws Exception
{
IPDO pdo = new PDODummy();
MyClass handler = new MyClass ();
MyClass handler2 = spy(handler);
when(handler2.getIPDO()).thenReturn(pdo);
PDOUtil.setPDO(pdo, LogicalFieldEnum.P_TX_CTGY, "test123");
IPDO pdoNew = handler2.getIPDO();
Assert.assertEquals("test123,(PDOUtil.getValueAsString(pdoNew, LogicalFieldEnum.P_TX_CTGY)));
}
However the when(handler2.getIPDO()).thenReturn(pdo); is throwing the Exception that I want to avoid ( because handler2.getIPDO() ) seems to call the real method.
Any idea on how to test this part of code?
A good technique for getting rid of static calls on 3rd party API is hiding the static call behind an interface.
Let's say you make this interface :
interface IPDOFacade {
IPDO getContextPDO();
}
and have a default implementation that simply calls the static method on the 3rd party API :
class IPDOFacadeImpl implements IPDOFacade {
#Override
public IPDO getContextPDO() {
return Util.getContextPDO();
}
}
Then it is simply a matter of injecting a dependency on the interface into MyClass and using the interface, rather than the 3rd party API directly :
public class MyClass {
private final IPDOFacade ipdoFacade;
public MyClass(IPDOFacade ipdoFacade) {
this.ipdoFacade = ipdoFacade;
}
private IPDO getIPDO() {
return ipdoFacade.getContextPDO();
}
public String handleIn(Object input) throws Throwable
{
String result = "";
IPDO pdo = getIPDO();
someImportantBusinessLogic(pdo);
return result;
}
...
}
In your unit test, you can then easily mock your own interface, stub it any way you like and inject it into the unit under test.
This
avoids the need to make private methods package private.
makes your tests more readable by avoiding partial mocking.
applies inversion of control.
decouples your application from a specific 3rd party library.
Changed my testing to :
#Test
public void testHandleIn() throws Exception
{
IPDO pdo = new PDODummy();
MyClass handler = new MyClass ();
MyClass handler2 = spy(handler);
doReturn(pdo ).when( handler2 ).getIPDO();
PDOUtil.setPDO(pdo, LogicalFieldEnum.P_TX_CTGY, "test123");
IPDO pdoNew = handler2.getIPDO();
Assert.assertEquals("test123,(PDOUtil.getValueAsString(pdoNew, LogicalFieldEnum.P_TX_CTGY)));
}
Solved after reading Effective Mockito.
when(handler2.getIPDO()).thenReturn(pdo);
Will actually call the method and then return pdo regardless.
Whereas:
doReturn(pdo).when(handler2).getIPDO();
Will return pdo without calling the getIPDO() method.

Categories

Resources