Mock a static field in a Spring JUnit test - java

I am currently working on a Spring boot project. I'm writing a JUnit 5 test for a class which is as follows,
class TheClassUnderTest {
public String methodToTest() {
Map<Integer, Object> collection = SomeOtherClass.someStaticField;
/*
Some processing logic
*/
}
}
I want to know if there is a way to mock the usage of "SomeOtherClass.someStaticField" so that I can test my class "TheClassUnderTest". I also use Mockito, so any answers using Mockito are also welcome

Mockito added support for static methods moving since Mockito 3.4.0, and before that you could use powerMockito to achieve this.
Having said that, what you are asking. Mocking static field is not suuportrd by mockito and actually Mockito does not support mocking class fields at all, only methods.
I would suggest wrapping the static variable in some method, and preferably make it non static.
Generally avoid static methods, as a class depending on static method of another class is strongly coupled with it and is bad practice for TDD.

Related

Stubbing Static Factory in CUT with Mockito

My class under test is ClassA which in one of its private method uses a static factory (lets say CarFactory) method getCar(XXX xxx) which returns a Car.
Part of the CarFactory logic is to validate that the given xxx parameters meets some criteria.
I tried using Mockito like the following:
#Mock private Car mockForCar;
#Mock private XXX xxxMock;
...
when(CarFactory.getCar(xxxMock)).thenReturn(mockForCar);
But I get an exception regarding that xxxMock isn't valid by the CarFactory.
Why is the real getCar(xxx) method gets called and not the stubbed one?
Is there a better way doing this?
From the Mockito FAQ:
Can I mock static methods?
No. Mockito prefers object orientation and dependency injection over
static, procedural code that is hard to understand & change. If you
deal with scary legacy code you can use JMockit or Powermock to mock
static methods.
If you want to stub this using Mockito, you should make it non-static and inject the factory. And that's better OO design anyway.

How to mock static methods with mockito?

I am using mockito for the Junits
I know mockito donot mock static methods but is there a way around for this instead of using powermock?
Thanks
Possible workaround would be to encapsulate static methods in real instance I think. Or real instance behind the static method.
Though that would mean you'll have to modify your production code.
Honestly if you ask yourself this question now, you are testing your code too late in the development process. (Now evangelizing ;)) If you were practicing TDD, you would have noticed this issue early, and tweaked your design early to be fully testable with classic testing software.
I personally use the "pain metrics" when practicing TDD to see if my design is ok or not. Of course everything depends on the context, but usually this is a good indicator of good design (at least for me and some others).
So my advice get rid of these static methods or revise your design to not be dependent on static method mocking.
Cheers
Not sure what "way around" you are looking for. A lot of people use both Mockito and Powermock together and I've not heard any horror-stories about incompatibilities or conflicts. Just use Powermock in those instances where you need to mock static methods and you should be ok.
Or refactor to not use static methods in a way that requires mocking.
No i think there isn't any way to do this withour PowerMock.
But you could break the dependency on this static methods, by introducing an adapter.
Mockito supports mocking static methods since version 3.4.0.
And it does the job better than PowerMock by limiting the scope of the static method mock.
To use this feature, you must enable Mockito's inline mock maker by adding the following file into the test-classpath:
/mockito-extensions/org.mockito.plugins.MockMaker
The contents of the file must be the following single line:
mock-maker-inline
When you've done this, you can mock final classes and static methods.
Here an example of how to mock static methods with and without arguments:
public class Foo {
public static String voidMethod() {
return "voidMethod-return";
}
public static String intMethod(int x) {
return "intMethod-return " + x;
}
}
...
// Prepare class 'Foo' for static mocking, for the current thread:
try (MockedStatic<Foo> mocked = Mockito.mockStatic(Foo.class)) {
//////////
// Mock 'Foo.voidMethod()' to return "voidMethod-mock":
mocked.when(Foo::voidMethod).thenReturn("voidMethod-mock");
assertEquals("voidMethod-mock", Foo.voidMethod());
mocked.verify(Foo::voidMethod);
//////////
// Mock 'Foo.intMethod()' to return "intMethod-mock":
mocked.when(() -> Foo.intMethod(10)).thenReturn("intMethod-mock 10");
assertEquals("intMethod-mock 10", Foo.intMethod(10));
mocked.verify(() -> Foo.intMethod(10));
} // MockedStatic.close() releases the static mock.
// The original static method is 'restored' here:
assertEquals("voidMethod-return", Foo.voidMethod());
assertEquals("intMethod-return 10", Foo.intMethod(10));

PowerMock + Mockito VS Mockito alone

Can anyone please summarize, what exactly features gives you adding PowerMock on top of the Mockito?
So far I've found these:
mock static, final and private methods
remove static initializers
allow mocking without dependency injection - this one isn't clear to me. Can you elaborate?
Does it add anything else? Can you please sum up in several lines?
And do I need to sacrifice something when using PowerMock?
I don't know of other benefits offhand, but I want to address 2 of your sub-questions (and this is way too long for a comment):
allow mocking without dependency injection - this one isn't clear to me. Can you elaborate?
I think this came from the Motivation wiki page where they describe a way of refactoring code to not invoke static methods to make it testable. For a concrete example of what I think they're getting at, let's say you have this code and you want to test the method mocking the behaviour of the static method, without using powermock:
public class MyClass {
public void doGetString() {
...
OtherClass.getString(); //It's complex and scary and needs mocking!
...
}
}
One solution, would be to pull the static invocation into its own object, then inject an object that can be mocked come test time. For example, without using other frameworks, this could look like:
public class MyClass {
public static class StringGetter {
public getString() {
return OtherClass.getString();
}
}
private final StringGetter getter;
//Existing Constructor
public MyClass() {
this(new StringGetter());
}
//DI Constructor
MyClass(StringGetter getter) {
this.getter = getter;
}
public void doGetString() {
...
getter.getString();
...
}
}
I've seperated the behaviour of my method from the behaviour of the static invocation, and can use the DI constructor to inject mocks easily at test time. Of course with powermock I could just mock the static method in place, and run with it.
And do I need to sacrifice something when using PowerMock?
Physically no, but I'd say philosophically yes :). The below are my opinions, and I try to give good reasons behind them, but of course they are opinions so take them with a grain of salt:
The potentially scary thing that is happening with PowerMock is that in order to accomplish the feats of mocking private and static methods, they are using a custom class loader (which shouldn't be present at runtime in production) and changing the bytecode of your classes. Arguably, this should not matter with the vast majority of classes most of the time, but if you think about it, if the bytecode has changed, and certain side effects are no longer present, you're effectively testing different Classes albiet based upon your existing Classes. Yes this is a very academic argument.
You can somewhat mitigate this first argument by having good comprehensive integration and higher level tests that don't use PowerMock. In this way you can be more confident in the behaviours of your objects even if your unit tests are using PowerMock.
The other argument I have against PowerMock, is that it could almost too easily become a crutch. I agree that PowerMock can help with testing code that uses legacy code and other code that you do not have control over. However I would argue that when you have control over the classes that you need to mock, you should avoid its use. If you write a class with a private method or static method that you need to explicitly mock in order to test other methods, my gut instinct would say that this method may be doing too much and should be refactored and broken up. Having PowerMock already available in a project, you may be tempted to just mock it and move on, which would mitigate the pain that should encourage you to refactor the same. Yes there are sometimes due to various technical and non-technical constraints this is not possible, but it's good to solve pain points instead of avoid them :)
PowerMock is an extension to Mockito that allows mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more.
Another feature of the Powermock mockito extension is that it supports mocking and stubbing of equals and hashcode.
As with all powermock features to be used with care, but adding (value-based) equality for specific results can be helpful.
One more feature of PowerMock is that we can mock construction of new objects in a method. It is helpful when we cannot change the code of the method to be tested.
For mocking final class we can use org.mockito.plugins.MockMaker. What you would need to do is
Create a folder in your test/resource folder with namemockito-extensions.
Create a file under it with the name org.mockito.plugins.MockMaker.
In that file have just one line mock-maker-inline
This will not require you to do add any new library and hence save some runtime.

Why doesn't Mockito mock static methods?

I read a few threads here about static methods, and I think I understand the problems misuse/excessive use of static methods can cause. But I didn't really get to the bottom of why it is hard to mock static methods.
I know other mocking frameworks, like PowerMock, can do that but why can't Mockito?
I read this article, but the author seems to be religiously against the word static, maybe it's my poor understanding.
An easy explanation/link would be great.
I think the reason may be that mock object libraries typically create mocks by dynamically creating classes at runtime (using cglib). This means they either implement an interface at runtime (that's what EasyMock does if I'm not mistaken), or they inherit from the class to mock (that's what Mockito does if I'm not mistaken). Both approaches do not work for static members, since you can't override them using inheritance.
The only way to mock statics is to modify a class' byte code at runtime, which I suppose is a little more involved than inheritance.
That's my guess at it, for what it's worth...
If you need to mock a static method, it is a strong indicator for a bad design. Usually, you mock the dependency of your class-under-test. If your class-under-test refers to a static method - like java.util.Math#sin for example - it means the class-under-test needs exactly this implementation (of accuracy vs. speed for example). If you want to abstract from a concrete sinus implementation you probably need an Interface (you see where this is going to)?
Mockito [3.4.0] can mock static methods!
Replace mockito-core dependency with mockito-inline:3.4.0.
Class with static method:
class Buddy {
static String name() {
return "John";
}
}
Use new method Mockito.mockStatic():
#Test
void lookMomICanMockStaticMethods() {
assertThat(Buddy.name()).isEqualTo("John");
try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
theMock.when(Buddy::name).thenReturn("Rafael");
assertThat(Buddy.name()).isEqualTo("Rafael");
}
assertThat(Buddy.name()).isEqualTo("John");
}
Mockito replaces the static method within the try block only.
As an addition to the Gerold Broser's answer, here an example of mocking a static method with arguments:
class Buddy {
static String addHello(String name) {
return "Hello " + name;
}
}
...
#Test
void testMockStaticMethods() {
assertThat(Buddy.addHello("John")).isEqualTo("Hello John");
try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) {
theMock.when(() -> Buddy.addHello("John")).thenReturn("Guten Tag John");
assertThat(Buddy.addHello("John")).isEqualTo("Guten Tag John");
}
assertThat(Buddy.addHello("John")).isEqualTo("Hello John");
}
Mockito returns objects but static means "class level,not object level"So mockito will give null pointer exception for static.
I seriously do think that it is code smell if you need to mock static methods, too.
Static methods to access common functionality? -> Use a singleton instance and inject that
Third party code? -> Wrap it into your own interface/delegate (and if necessary make it a singleton, too)
The only time this seems overkill to me, is libs like Guava, but you shouldn't need to mock this kind anyway cause it's part of the logic... (stuff like Iterables.transform(..))
That way your own code stays clean, you can mock out all your dependencies in a clean way, and you have an anti corruption layer against external dependencies.
I've seen PowerMock in practice and all the classes we needed it for were poorly designed. Also the integration of PowerMock at times caused serious problems(e.g. https://code.google.com/p/powermock/issues/detail?id=355)
PS: Same holds for private methods, too. I don't think tests should know about the details of private methods. If a class is so complex that it tempts to mock out private methods, it's probably a sign to split up that class...
In some cases, static methods can be difficult to test, especially if they need to be mocked, which is why most mocking frameworks don't support them. I found this blog post to be very useful in determining how to mock static methods and classes.

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