Using PowerMockito and Mockito to test call to other artifact's method - java

I am sure this is quite a common question now, but I really can't get away with this issue I am having on mocking private method which internally calls another method and returns a collection.
Class that I am testing has a public method which calls private method to get Collection object. I use PowerMock to create a spy of private method.
public void method1(String s)
{
Collection<Object> list = invokePrivate()
}
private Collection<Object> invokePrivate()
{
Wrapper wrapperObj = Factory.getInstance.getWrapper();
Collection<Object> list = wrapperObj.callWrapperMethod(); // This always calls into real method, instead of mocked version.
return list;
}
Test Class-:
So In order to test public method "method1" I create a spy using PowerMockito to spy over private method and return a demo list.
MainClass obj = new MainClass();
MainClass spy = PowerMockito.spy(obj);
PowerMockito.when(spy, method(MainClass.class, "inokePrivate"))
.thenReturn(list); // demo list which exists as a test class member.
Above calls into private method which in turns tries to call wrapperObj.callWrapperMethod() which resides in a different artifact and breaks there because some implementation it doesn't find there.
So I try to mock wrapperObj.callWrapperMethod.
WrapperClass wr = new WrapperClass();
WrapperClass spy1 = PowerMockito.spy(wr);
when(spy1.callWrapperMethod()).thenReturn(list) // demo list which exists as a test class member.
Above mocking again calls into actual implementation of callWrapperMethod() and breaks in there.
How can I prevent calling into actual implementation of wrapper method?
Few of the answers that helped me-:
Mockito:How to mock method called inside another method
Testing Private method using mockito
[UPDATE] -: as suggested as I did following-:
PowerMockito.doReturn(list).when(spy1).callWrapperMethod(); // This returns me demo list successfully.
But now when I call private method from PowerMockito control goes into invokePrivate method and again tries to call original callWrapperMethod instead of return list from spy version.

I suggest to not do it this way. Your private method should not retrieve the singleton factory object using a static method.
Static stuff breaks "easy" mocking; forces you to use "power" mocking; and thereby, creates more problems than it solves.
Change your code to use dependency injection. Do something like this:
class YourClass {
private final Factory factory;
public YourClass() {
this(Factory.getInstance(); }
YourClass(Factory theFactory) {
this.factory = theFactory;
...
This will allow you to use the second constructor in your unit test; to provide a (easily mocked) factory object for your class. Thereby you eliminate the whole need for PowerMock.
Long story short - when code is hard to test; change the code; and not the test. As a side effect, you are improving the quality of your code - because you loose the hard dependency on that singleton object.
And just to be complete: I also recommend to avoid "breaking" the Law of Demeter ( http://en.wikipedia.org/wiki/Law_of_Demeter ): if your class needs the wrapper; then it should hold a wrapper object; if it needs that factory; then it should hold a factory object. But you should not hold one object ... to retrieve another object from there, to run something on that second object. As you see - doing so leads exactly to the sort of problem that you are facing.

Related

Mocking the arguments passed to callbacks (lambdas)

How would I mock methods that accept a lambda using Mockito so that I am able to control which arguments are passed into the callback? I am specifically trying to mock the JDBI method useExtension which is used like this:
jdbi.useExtension(OrgUnitDao.class, dao -> {
// Skip if already loaded
// Skip if already loaded
if (dao.orgUnitsAreLoaded()) {
I would like to substitute the dao object passed back into the callback so that I could control the branching using the return value of dao.orgUnitsAreLoaded().
The signature looks like this
public <E,X extends Exception> void useExtension(Class<E> extensionType,
ExtensionConsumer<E,X> callback)
throws NoSuchExtensionException,
X extends Exception
This is the full answer to my question. It's simplified down to the very basics of how to do the stubbing and so doesn't reflect the production code I am to test, but it shows exactly the mechanics needed to do it.
final Jdbi jdbi = mock(Jdbi.class);
doAnswer(invocation -> {
System.out.println("this is the doAnswer lambda - just setting up the answer and the mocks");
final Class<OrgUnitDao> daoClass = invocation.getArgument(0);
final ExtensionConsumer callback = invocation.getArgument(1);
final OrgUnitDao mock1 = mock(daoClass);
when(mock1.orgUnitsAreLoaded()).thenReturn(false);
// call the actual callback method
callback.useExtension(mock1);
return null;
}).when(jdbi).useExtension(eq(OrgUnitDao.class), any());
// This is the method call I am to test
// Regard this as hidden away in some outer method in
// the System-Under-Test, but that I have been able
// to inject all its dependencies
jdbi.useExtension(OrgUnitDao.class, new Foo());
/// Further down, outside of the method
// Only replaced the lambda with this to get toString() for debugging ...
class Foo implements ExtensionConsumer<OrgUnitDao, RuntimeException> {
#Override
public void useExtension(OrgUnitDao orgUnitDao) throws RuntimeException {
System.out.println("A real method call, now using the passed in mocked dao:" + orgUnitDao.orgUnitsAreLoaded());
}
#Override
public String toString() {
return "OrgUnitDao class";
}
}
To parallel the conversation on the question "Calling callbacks with Mockito", your lambda might be called synchronously during the execution of your method-under-test, or it might be called later based on some external factor or interaction. Like Dawood's answer there, your answer here using a Mockito Answer will work, and is the only way to go if you are looking for the synchronous style (where mockJdbi calls your lambda immediately before methodUnderTest returns). If your lambdas are going to be called asynchronously, or if your system tolerates you calling the lambda asynchronously, you might want to test the state after your method-under-test returns but before you interact with the lambda.
// MockitoJUnitRunner, MockitoRule, or MockitoAnnotations.initMocks populate these.
// Especially useful for the ArgumentCaptor's generic arguments.
#Mock Jdbi mockJdbi;
#Mock OrgUnitDao mockOrgUnitDao;
#Captor ArgumentCaptor<ExtensionConsumer<OrgUnitDao, RuntimeException>>
extensionConsumerCaptor;
#Test public void yourTest() throws Exception {
// No stubbing needed! Just create the system under test.
YourSystemUnderTest systemUnderTest = new YourSystemUnderTest(mockJdbi);
// Call the method under test, which presumably calls useExtension(...).
systemUnderTest.methodUnderTest();
// Assert anything that should be true before the lambda is called.
assertFalse(systemUnderTest.getSomeState());
// Confirm that useExtension was called, and simultaneously acquire the lambda.
// ArgumentCaptor.capture() is a matcher, so every argument requires a matcher like eq.
verify(mockJdbi).useExtension(eq(OrgUnitDao.class), extensionConsumerCaptor.capture());
// Prepare the mock DAO and call the lambda.
when(mockDao.getFoo()).thenReturn("bar");
extensionConsumerCaptor.getValue().useExtension(mockDao);
// Assert anything that should be true after the lambda is called.
assertTrue(systemUnderTest.getSomeState());
}
Though lambdas reduce the boilerplate previously associated with anonymous inner classes, you may also prefer using the Captor style because it saves you from creating lengthy Answer implementations and hiding your test assertions or Mockito verifications in them. This is especially tempting if your project prefers BDD-style mocks with clear "given-when-then" structure (though my example more-closely resembles "given-when-then-when-then").

PowerMockito verify private method called x times

I'm using PowerMockito and spy to mock private methods:
final SomeClass someClass = new SomeClass();
final SomeClass spy = PowerMockito.spy(someClass);
PowerMickito.doReturn("someValue", spy, "privateMethod1");
final String response = Whitebox.invokeMethod(spy, "anotherPrivateMethod");
// I can now verify `response` is of the correct data
// But I also want to verify `privateMethod1` was called x times or so
I cannot figure out how to verify that my method was called x times.
Side note
Is it better to just make all my private methods protected and then extend that class in my test class and do that?
This will do.
PowerMockito.doReturn("someValue", spy, "privateMethod1");
final String response = Whitebox.invokeMethod(spy, "anotherPrivateMethod");
assert(response)
verifyPrivate(spy, times(1)).invoke("anotherPrivateMethod", "xyz");
I am assuming your private method(anotherPrivateMethod) takes one argument "xyz". Which you can modify according to your private method declaration.
Testing private methods is testing implementation details.
If you choose to change the implementation the tests become worthless and will be thrown away.
You should strive to test the What, not the How. Then the tests will survive even if you change implementation.
A wonderful paper on how to avoid testing incidental details can be found here.

Writing testable code when new object is being constructed using Mockito only

So I am writing a class which I want to follow the best practices and be testable.
I have a new object to be created inside it. So, I am following the factory pattern to achieve it.
public class Apple {
// factory object injected in class
private SeedFactory seedFactory;
// Method to be tested
public void myMethod(String property1, int property2, String depends) {
// Just to set the necessary parameter
seedFactory = new SeedFactory(property1, property2);
// Factory pattern intact. Instance generation depends on only one parameter
SeedFactory result = seedFactory.getInstance(depends);
}
}
EDIT: Adding code for factory as well.
public class SeedFactory{
String property1;
int property2;
SeedFactory(property1,property2){
this.property1 = property1;
this.property2 = property2;
}
SeedFactory getInstance(int depends){
if(depends == 1)
{ // do stuff }
else{ // do stuff and return instance }
Now, before I actually create the new object, I have to make sure that I set two properties for the new instance to be generated, which are needed to be present irrespective of the type of instance generated by the factory. depends is the actual parameter which tells the factory what instance to return.
Now, as far as testability of this code is concerned, I can user PowerMockito to mock the factory object using whenNew but using PowerMockito is not a choice. I have to make it testable without it.
Also, I have tried to encapsulate the new call within a one line function and then use spy. But I want to avoid using spy, since it is not considered a good practice, in context of where this code is being used as a whole.
So my question is, Is there any way, without using PowerMockito, to re-write this class so that it can be unit tested properly?
If the instance to be generated needed only one parameter, then it would have been trivial. However, I don't want to pass more than one parameter to getInstance().
SeedFactory is not Apple's dependancy but your method depends on SeedFactory which has "uses" relationship. So to define proper relation i would suggest you use "USES" relation as below:
public void myMethod(SeedFactory seedFactory, String depends){ // Method to be tested
Now you could mock SeedFactory and can unit test it appropriately.
I think you're doing something wrong.
If SeedFactory isn't an Apple's dependency but an internal concern, hence you don't need to mock a SeedFactory to test Apple. You should test the public API provided by Apple only.
If SeedFactory is an Apple's dependency, so it definitely should be injected.

JUnit/Spring/Mockito - Unable to mock class returned from another class implementing ApplicationContextAware

I am new to Spring and JUnit. I need to mock a class which is derived from ApplicationContextAware class which is inside my toBeTested(getList) method. In the following short code snippet, I need to test the getList method in abc class.
I am able to mock ModulesConfigRegistry because there is a setter for it. But I am not able to mock ModuleConfig and ListProvider. Both ModulesConfigRegistry and ModuleConfig have implemented ApplicationContextAware so it returns classes from bean. ListProvider.getList(lst.getList in code) is the method which makes further calls up to database and is required to be mocked. Appreciate your help in advance. Code sample will be helpful as I am new to Spring and JUnit.
class abc {
private ModulesConfigRegistry modulesConfigRegistry;
public void setModulesConfigRegistry(ModulesConfigRegistry modulesConfigRegistry) {
this.modulesConfigRegistry = modulesConfigRegistry;
}
public List getList(String name, String moduleName)
{
ModuleConfig moduleConfig = modulesConfigRegistry.getModuleConfig(moduleName);
Object mlist = moduleConfig.getListProvider(name);
if(mlist instanceof ListProvider)
{
ListProvider lst = (ListProvider)mList;
}
return lst.getList("abc");
}
}
Maybe there is another more simple way to achieve this (not mandatory the best). In my experience I've used Reflection in Java when it's up to Unit-testing. After all, to me the main purpose of the unit tests is to simply exercise smallest testable part and nothing more. That's why I simply use my dummy-test-object and get/set fields/properties I need.
But one thing that must be considered here is that reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects. So if you know what your doing it's a good alternative.
Since you already using
JUnit
One very common use case in Java is the usage with annotations. JUnit 4, for example, will use reflection to look through your classes for methods tagged with the #Test annotation, and will then call them when running the unit test.
If you want to consider it and use it - here you can find some good examples.
Cheers.
One approach here is create mock objects for each object that you need to interact with ModuleConfig and ListProvider
#RunWith(MockitoJUnitRunner.class)
public class abcTest{
#InjectMocks
private abc abcInstance;
#Mock
private ModulesConfigRegistry modulesConfigRegistry ;
#Test
private voidTestGetList(){
//Create the mock and interactions
ModuleConfig moduleConfigMock = Mockito.mock(ModuleConfig.class);
ListProvider listProviderMock = Mockito.mock(ListProvider.class);
ArrayList listToReturn = new ArrayList();
Mockito.when(modulesConfigRegistry.getModuleConfig(Mockito.anyString())).thenReturn(moduleConfigMock);
Mockito.when(moduleConfigMock.getListProvider(Mockito.anyString())).thenReturn(listProviderMock);
Mockito.when(listProviderMock.getList(Mockito.anyString())).thenReturn(listProviderMock);
//Call real method
List resultList = abcInstance.getList("stringInput1", "stringInput2");
//Make assertions
}
}
Basically you need to create mock objects for any of the instances that you get from a mock object and use mockito to define the result of its method.
Other options is create a new class that implements or is a subclass of the returned object type and override the methods.

How to mock Objects that are not passed as arguments

Imagine the following class
public class ClassToBeTested{
private AnotherClass otherClass;
public void methodToBeTested(){
otherClass = new AnotherClass();
String temp = otherClass.someMethod()
// ...some other code that depends on temp
}
}
Now, if methodToBeTested was designed to accept an instance of AnotherClass I could easily create a mock of AnotherClass and tell Mockito to return a value i prefeer when someMethod() is called. However as the above code is designed AFAIK it's not possible to mock AnotherClass and testing this method will depend on what someMethod() returns.
Is there anyway I can test the above code without beeing dependent on what someMethod() returns using Mockito or any other framework?
If available you can use the Spring ReflectionTestUtils setField method:
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/test/util/ReflectionTestUtils.html#setField%28java.lang.Object,%20java.lang.String,%20java.lang.Object%29
If not write your own its pretty straight forward using reflection, some info here:
http://www.java2s.com/Code/Java/Reflection/Setprivatefieldvalue.htm
Something like the below, you will need additional error handling to get this to work properly:
public void setField(Object obj, String fieldName, Object value) {
Field f = obj.getDeclaredField(fieldName);
f.setAccessible(true);
f.set(obj, value);
}
It can then be called like this:
setField(objUnderTest, "fieldToSet", mockObject);
edit
I have just noticed that you are instantiating it inside the method. If that is absolutely necessary then you should follow the possible duplicate link posted by cyroxx.
Although that practice is often a sign of bad design so if you can take it out I would.
Setting the field by reflection as suggested in the other answer will work.
But if you're doing this sort of thing often, I'd recommend PowerMock (in conjunction with Mockito) or JMockIt to achieve this. Both allow you to mock constructors, statics, final fields... in short, just about anything. Very useful with legacy code.
However, when you're writing new code, and your class has a dependency on another class that you want to isolate in this way, you should consider changing the design so that the other object is passed in to your class instead of being instantiated by it. Search for "Dependency injection" and you'll find plenty...
As a quick fix, I usually wrap the call to new:
protected newAnotherClass() { return new AnotherClass(); }
That way, I can overwrite this method from a unit test. It's dirty but it's quick :-)
Here is a JMockit test which does what you want, very simply:
#Test
public void testTheMethodToBeTested(#Mocked final AnotherClass dep)
{
new NonStrictExpectations() {{ dep.someMethod(); result = "whatever"; }};
new ClassToBeTested().methodToBeTested();
new Verifications() {{
// verify other calls to `dep`, if applicable...
}};
}

Categories