JUnit: Intercepting a method call and then invoking with different params - java

I am working on junit and using PowerMockRunner to mock static methods.
I am aware that static methods can be mocked using when(...).thenReturn(...)
I need to mock a certain method that takes four arguments:
public static void addInputPath(String, Boolean, Integer, Double)
I need the third parameter(Integer) in any call to this method to be replaced by, say 10. All other parameters should just be passed as is.
In other words, I need to do something like this:
when(addInputPath(str, bool, intgr, dbl)).thenReturn(addInputPath(str, bool, 10, dbl));
Is there a way to do this?

So, when I get your requirements right, what you actually want to do is to intercept the call to addInputPath() and invoke it with a different parameter?
If so: I am not sure if this can be done with any mocking framework (and I doubt that it is possible). Mocking frameworks are about mocking calls; not about instrumenting/intercepting calls.
Coming back to your problem, this is a nice example why static calls far too often cause problems. Thus, the best solution in my eyes would be to change your method xyz() to avoid that thing calling addInputPath() directly. Like this:
interface InputPathAdder {
void addInputPath(str, ... );
}
class ForwardingInputPathAdder implements InputPathAdder {
// implements the method by calling the static method
and all of a sudden, you can also do:
class ForwardingInputPathAdderWithFixedIntegerParm implements InputPathAdder {
// implements the method by calling the static method, but using 10 always
( obviously, naming could be improved here )
And now: you use dependency injection to give your "class under test" some Object implementing InputPathAdder. This could be either one that is completely mocked for testing; or it could be one that just does forwarding (in your production environment; or it could be the one that fixes the 3rd parameter). And no need for mocking for your "intercept" situation.

Related

In JUnit-5, How do I mock a static method that returns void? Can we use import org.mockito.MockedStatic?

I have a few 3rd parties static util methods in my project, some of them just pass or throw an exception. There are a lot of examples out there on how to mock a static method using PowerMock but Junit5 doesn't support PowerMock, which has a return type other than void. But how can I mock a static method that returns void to just "doNothing()"?
Don't mock it. From your minimal description, you could replace the usage sites with Consumer and provide a mock of that. (You can even initialize the fields with method references to the static methods and just have setter methods to override them.)
However, the fact that the class under test calls these static methods is usually just an implementation detail that the test shouldn't care about, only checking observable behavior.
Build a wrapper class on it, call the wrapper method, and you can have a different wrapper in your test if you can do behavior differently or have the wrapper to call a class/method can be mocked ,

Mockito - how to mock, and express expectations, on an abstract method of a class (i.e. a callback)

I'm trying to unit-test an abstract class, therefore need to provide a mock implementation to the class' abstract methods.
I think I'm in a niche situation (!) since neither #Mock or #Spy seem to help.
tried Mockito.mock(SimpleClient.class, Mockito.CALLS_REAL_METHODS) but this totally shatters my abstract class (creates it without calling the constructor, running into NPE)
tried #Spy but this either requires an instance of the real class (which I cannot provide since it's abstract duh), or, it will attempt to call a no-arg constructor which doesn't exist.
(Context, although you should not need it: the class is a messaging client e.g. has sendMessage() and abstract onMessage() methods, and obviously I need to use the real implementation of sendMessage() and mock the callback abstract onMessage())
I found the following
to go the first approach (Mockito.mock), they have added the ability to construct an underlying real object properly using an arbitrary constructor (And hopefully after that, Moquito goes on to "stub" each method as you express expectations on it, like the below):
MyClass mock = Mockito.mock(MyClass.class, Mockito.withSettings()
.useConstructor("stringArg", 17)
.defaultAnswer(Mockito.CALLS_REAL_METHODS));
// ...
Mockito.when(mock.onMyAbstractMethod(Mockito.anyInt())).then(
invocation -> mock.callAnotherRealMethodOnTheMock(invocation.getArgument(0)));
to go the second approach indeed a #Spy needs a created instance of the class, so in that case you really need to subclass it first.
Extra note: a separate issue, ugly as well, happens if say onMyAbstractMethod returns void, in that case the Mockito.when... syntax doesn't work due to a language limitation it seems, a fact which is poorly documented. One needs to do it the other way around and say:
Mockito.doAnswer(invocation -> mock.callAnotherRealMethodOnTheMock(invocation.getArgument(0)))
.when(mock).onMyAbstractMethod(1);

Ignoring argument

So I'm trying to test a method methodUnderTest which is something like this:
methodUnderTest{
//Other stuff that works nice
this.setterMethod(OtherClass.methodThatErrors(arg1));
}
So I'm trying to avoid that static method call methodThatErrors.
What I'm doing so far:
ClassUnderTest spy = Mockito.spy(objectOfClassUnderTest);
Mockito.doNothing().when(spy).setterMethod(Mockito.any(OtherClass.class));
However this does not work, the method is still being called. I would've thought that it shouldn't call the argument method at all because I've written any for the argument of setterMethod. So how can I prevent this call using Mockito, not PowerMockito.
Edit:
So I managed to mock it by moving the static method call like so:
methodUnderTest{
this.extraSetterMethod(arg1);
}
extraSetterMethod(arg1){
this.setterMethod(OtherClass.methodThatErrors(arg1));
}
I don't really like this solution because it's adding several extra lines of code (even more with javadoc) which just makes the class messier.
The problem here is that the value is coming directly from the static method, and not the setter itself. Whatever value it's getting is coming from the real invocation of the method itself. Mocking out the call to the setter has no effect; it's not the result of the setter that's in error.
This is a scenario in which you have to make a hard decision:
Introduce a parameter to the method so that the call can be easier to mock, or
Use PowerMockito to mock out the call.
I strongly encourage the latter, especially if you're dealing with a legacy code base which is not very forgiving to a signature change.

Getting the annotations of the calling method

Here is an example of my code:
class foo extends afoo{
#HTTPPost
returnClass runTransaction(RequestData req){
return sendData(req, returnClass.class)
}
#HTTPGet
returnClass runTransaction2(RequestData req){
return sendData(req, returnClass.class)
}
}
abstract class afoo {
public <T> T sendData(ARestMessage req, Class<T> returnClassType)
//here i need the annotation of the calling method
}
Basically i'm building a pretty complex messaging system and I want to put as much of the switching and configuration in annotations as i can.
Yes, I know there are a few libraries out there (like Google reflection) that would make this easier but in order for me to use them I have to do 4-6 months of paperwork and meetings with Enterprise Architecture to get approval to use them. Seeing the project must be finished in 2 months, i'm doing it by hand.
So what i'm doing is creating annotations that developers can annotate the methods with indicating the way the resulting service is expecting the data to be sent. That could be a get, post, put, etc. Inside the abstract class, that all service classes extend, is a senddata method. That method must be able to figure out which method was used to call it, aka, was it by runTransaction or runTransaction2, so sendData pull that methods annotations and therefore know exactly how to send the data to the service.
now I found this (which is the first line of code in my sendData method)
final Method callingMethod = this.getClass().getEnclosingMethod();
But it keeps returning null. i've read the javadoc on it several times and i'm not understanding why it keeps returning null.
I understand that I can get the parent caller using the stack, but I would prefer not to do that because this application shares app server memory with another application that does a TON of AOP work. That AOP work is really good at messing up stacks in unintended ways, so I would rather solve this using straight reflection.
Does anyone know why this method keeps returning null? Is it because its contained in an abstract class and not my foo class itself? Is there a way to accomplish this using the techniques I would prefer to use?
thanks
The method Class.getEnclosingMethod() does not do what you think it does. Here is the Javadoc for it:
If this Class object represents a local or anonymous class within a
method, returns a Method object representing the immediately enclosing
method of the underlying class. Returns null otherwise. In particular,
this method returns null if the underlying class is a local or
anonymous class immediately enclosed by a type declaration, instance
initializer or static initializer.
Specifically, it returns the outer, enclosing method for an anonymous inner class, that was defined in the context of that method. I did not see anywhere in your description that these messaging methods are being called from anonymous/local inner classes. Here is an example in code (jUnit required):
import java.lang.reflect.Method;
import org.junit.Assert;
import org.junit.Test;
interface Introspector {
public Method getEnclosingMethod();
}
public class Encloser {
public Encloser() {
super();
}
public Method noop() {
final Introspector inner = new Introspector() {
#Override
public Method getEnclosingMethod() {
return getClass().getEnclosingMethod();
}
};
return inner.getEnclosingMethod();
}
#Test
public void testEnclosingMethods() throws Exception {
final Encloser encloser = new Encloser();
Method method = encloser.getClass().getEnclosingMethod();
Assert.assertNull(method);
method = encloser.noop();
Assert.assertNotNull(method);
}
}
Your current solution sounds pretty complicated. Are you planning on walking up the method call chain (which you can only do by dumping the stacktrace btw) and looking for annotations after doing some hefty reflection? I foresee alot of bugs. Frankly, employing some kind of builder pattern would probably be better for your scenario.
There's no point using annotation here, just pass another argument to method sendData().

How can I easily mock out a static method in Java (jUnit4)

How do I easily mock out a static method in Java?
I'm using Spring 2.5 and JUnit 4.4
#Service
public class SomeServiceImpl implements SomeService {
public Object doSomething() {
Logger.getLogger(this.class); //a static method invoked.
// ...
}
}
I don't control the static method that my service needs to invoke so I cannot refactor it to be more unit-testable. I've used the Log4J Logger as an example, but the real static method is similar. It is not an option to change the static method.
Doing Grails work, I'm used to using something like:
def mockedControl = mockFor(Logger)
mockControl.demand.static.getLogger{Class clazz-> … }
…
mockControl.verify()
How do I do something similar in Java?
Do you mean you can't control the calling code? Because if you control the calls to the static method but not the implementation itself, you can easily make that testable. Create a dependency interface with a single method with the same signature as the static method. Your production implementation will just call through to the static method, but anything which currently calls the static method will call via the interface instead.
You can then mock out that interface in the normal way.
The JMockit framework promises to allow mocking of static methods.
https://jmockit.dev.java.net/
In fact, it makes some fairly bold claims, including that static methods are a perfectly valid design choice and their use should not be restricted because of the inadequacy of testing frameworks.
Regardless of whether or not such claims are justifiable, the JMockit framework itself is pretty interesting, although I've yet to try it myself.
PowerMock has this ability. It can also mock instantiations of objects inside the class under test. If your tested method calls new Foo(), you can create a mock object for that Foo and replace it in the method you are testing.
Things like suppressing constructors and static initializers are also possible. All of these things are considered untestable code and thus not recommended to do but if you have legacy code, changing it is not always an option. If you are in that position, PowerMock can help you.
public interface LoggerWrapper {
public Logger getLogger(Class<?> c);
}
public class RealLoggerWrapper implements LoggerWrapper {
public Logger getLogger(Class<?> c) {return Logger.getLogger(c);}
}
public class MockLoggerWrapper implements LoggerWrapper {
public Logger getLogger(Class<?> c) {return somethingElse;}
}
As another answer above stated, JMockit can mock static methods (and anything else, as well).
It even has direct support for logging frameworks. For example, you could write:
#UsingMocksAndStubs(Log4jMocks.class)
public class SomeServiceTest
{
// All test methods in this class will have any calls
// to the Log4J API automatically stubbed out.
}
Support for JUnit 4.4 was dropped, however. JUnit 3.8, JUnit 4.5+ and TestNG 5.8+ are supported.
That's one of the reason static methods are bad.
We re-architect ed most of our factories to have setters as well so that we could set mock objects into them. In fact, we came up with something close to dependency injection where a single method acted as a factory for all our singletons.
In your case, adding a Logger.setLogger() method (and storing that value) could work. If you have to you could extend the logger class and shadow the getLogger method with your own as well.
You could use AspectJ to intercept the static method call and do something useful for your test.
Basically, There isn't an easy way to do this in Java + Spring 2.5 & JUnit 4.4 at the moment.
Although it is possible to refactor, and abstract away the static call, Refactoring the code isn't the solution that I was looking for.
JMockit looked like it would work, but is incompatibile with Spring 2.5 and JUnit 4.4.

Categories