Guava #VisibleForTesting : Help me with a complete example - java

My intent is to do unit test of private methods and I understand on how to import the #VisibleForTesting and use it for a private method. I have done a quite a bit of search but unable to see a complete example that demonstrates this feature.
For eg:
class MyClass {
#VisibleForTesting
private double[] getWorkArray(double[] values,int length) {
:
:
return <some double array>
}
}
Now in JUnit, I must be able to do
#Test
public void testProvateMethod() {
MyClass object = new MyClass();
assertNotNull(object.getWorkArray(...);
}
But the difficult part is I am unable to comprehend/do the following
a) Snippet of maven compiler plugin for including the relevant annotation processor
b) Actually be able to test a private method. (since it throws error related to visibility of method)
I am unable to do it in action while I write a test in JUnit (due to the private access error). For eg: mvn clean test
Please provide a complete example to really all steps involved in getting the JUnit test of private methods done.

Firstly, I do not recommend to test private methods, unit tests should test public methods in most cases. If you have to test private methods, it usually indicates a bad design.
Regarding to #VisibleForTesting , it is used in package-methods in Guava, and not part of JUnit API. The annotation is just a tag to indicate the method can be tested, it even doesn't be loaded in JVM. So if you need to test non-public methods, make the methods package scope which is visible to unit test classes in same package.
Last, by using reflect can access private methods, if you really have to test them.

Testing a private method must be one of the bad patterns.
However, there are times when you often feel the urge to test private methods.
In this case, I personally use ReflectionTestUtils to test the method. This is because we wanted to keep the original intent of the private method, and only test the method. Below is an example of my sample.
MyClass myClass = new MyClass();
ReflectionTestUtils.invokeMethod(myClass, "getWorkArray", values, length);
One drawback is the fact that I get the name of the method as a String and it is quite a bit sad except for the fact that refactoring does not convert correctly in IDEA.
I hope it helps.
Thanks.

You can remove private keyword:
class MyClass{
#VisibleForTesting double[] getWorkArray(double[] values,int length) {
:
:
return <some double array>
}
}
Then you are able to:
MyClass object = new MyClass();
assertNotNull(object.getWorkArray(...);
in your test.

Related

Spring Mockito Mocked object keeps calling real method [duplicate]

I need mock some class with final method using mockito. I have wrote something like this
#Test
public void test() {
B b = mock(B.class);
doReturn("bar called").when(b).bar();
assertEquals("must be \"overrided\"", "bar called", b.bar());
//bla-bla
}
class B {
public final String bar() {
return "fail";
}
}
But it fails.
I tried some "hack" and it works.
#Test
public void hackTest() {
class NewB extends B {
public String barForTest() {
return bar();
}
}
NewB b = mock(NewB.class);
doReturn("bar called").when(b).barForTest();
assertEquals("must be \"overrided\"", "bar called", b.barForTest());
}
It works, but "smells".
So, Where is the right way?
Thanks.
From the Mockito FAQ:
What are the limitations of Mockito
Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
There is no support for mocking final methods in Mockito.
As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method. That said, there are some ways out through bytecode manipulation (e.g. with PowerMock)
A comparison between Mockito and PowerMock will explain things in detail.
You can use Powermock together with Mockito, then you do not need to subclass B.class. Just add this to the top of your test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(B.class)
#PrepareForTest instructs Powermock to instrument B.class to make the final and static methods mockable. A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.
Mockito 2 now supports mocking final methods but that's an "incubating" feature. It requires some steps to activate it which are described here:
https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
Mockito 2.x now supports final method and final class stubbing.
From the docs:
Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you create this file you can do:
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios.
Assuming that B class is as below:
class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}
There is a better way to do this without using PowerMockito framework.
You can create a SPY for your class and can mock your final method.
Below is the way to do it:
#Test
public void test() {
B b = new B();
b.setBar("bar called") //This should the expected output:final_method_bar()
B spyB = Mockito.spy(b);
assertEquals("bar called", spyB.bar());
}
Mockito can be used to mock final classes or final methods. The problem is, this doesn't come as out of the box feature from Mockito and needs to be configured explicitely.
So, in order to do that,
Create a text file named org.mockito.plugins.MockMaker to the project's src/test/resources/mockito-extensions directory and add a single line of text as below
mock-maker-inline
Once done, you can use the mockito's when method to mock the behaviour like any other regular method.
See detailed examples here
I just did this same thing. My case was that I wanted to ensure the method didn't cause an error. But, since it's a catch/log/return method, I couldn't test for it directly without modifying the class.
I wanted to simply mock the logger I passed in. But, something about mocking the Log interface didn't seem to work, and mocking a class like SimpleLog didn't work because those methods are final.
I ended up creating an anonymous inner class extending SimpleLog that overrode the base-level log(level, string, error) method that the others all delegate to. Then the test is just waiting for a call with a level of 5.
In general, extending a class for behavior isn't really a bad idea, and might be preferable to mocking anyway if it's not too complicated.

How to mock private enum using Powermock?

I have following class:
public class MyClazz
{
private static enum MyEnum
{
INSTANCE;
private MyClazzB getMyClazzB()
{
....
return
}
final MyClazzB b = getMyClazzB();
}
public void methodWhichIWantTest(arguments)
{
//...
//here is logic which I want to test
//...
MyEnum.INSTANCE.b.doSomething();//I want to mock this line.
}
}
I am not author of MyClazz and I do not want to change anything. I only want to test methodWhichIWantTest method. The problem is that method getMyClazzB throws exception. I do not how to mock it.
How to mock it? I think that I should mock MyEnum class but it is private.
===EDIT===
I think that I should clarify my question because I got some comments.
I am not author of MyClazz but this class is part of my project and I can edit this class but I would like to avoid editing as much as possible. I fixed some bug in private method of MyClazz. I would like to write some test which tests my fix. Testing private method is not good practice so I can write integration test or write unit test for some public method which calls this private method. Firstly I wanted to write integration test but after research I found that integration test is to complicated and takes me too much time. So I decided to write unit test for some public method which calls this private method. methodWhichIWantTest is this public method. Method getMyClazzB throws exception because it crates javax.naming.InitialContext and lookup some beans (It works properly on wildfly but it does not work inside simple unit test).
I think that I have following options:
do not test it
write integration test (it is time consuming)
try to mock MyEnum and write unit test
try to mock InitialContext and write unit test
edit source code, mock and write unit test.
test private method directly using java reflection
My question is related to point 3. I do not know how to realize point 3 I was curious how to do it so I asked my question.
I am afraid that realizing point 3 is not possible within a reasonable time.
Thank you for help.
how-to-mock-an-enum-singleton-class-using-mockito-powermock does not solve my issue because MyEnum enum is a private. E.g. I cannot use #PrepareForTest({MyEnum.class}) annotation because MyEnum is not accessible.

Mockito JUnit testing: check method call in constructor

I have a class Foo with private and public or protected methods. For example:
public class Foo{
private int number;
public Foo(){
setup();
doSthing();
}
private void doSthing(){
number=10;
}
public void setup(){
}
protected int getNumber(){
return number;
}
public void run(){
getNumber();
//Do blah blah...
}
}
And I am trying to test this class using Mockito.
public class FooTest
{
public void testMethods()
{
Foo foo = PowerMockito.mock (Foo.class);
//1 What should I do to see that setup() and doSthing()
//has been called on Foo construction
mock.run();
//2 What should I do to see that getNumber()
//has been called on run() method call
}
}
I am also hoping to include "times(1)" if possible. I'd appreciate your help.
You are getting this wrong:
First of all: please do not use any of the PowerMock... frameworks. They rely on byte code manipulation; and sooner or later that calls for trouble. Believe me, I have spent many hours hunting really strange errors for no good reasons.
Then: do not test your code this way!
You use a mocking framework to create/control those objects that you pass to your "class under test". You don't use the framework to directly test your "class under test"!
You also don't want to write test code that knows about private methods - those are implementation details.
What you do instead:
a) as said, you can use mocking to pass objects into your class under test. And then you can control/verify those mocks see the calls that you expect your "class under test" to make
b) you create objects of your "class under test" ... and then "assert" on the properties of those objects; or on results that method calls return.
Just to be precise: a mocked object ... doesn't know anything about the code in the "original" class. It is a mock! You can't use it for the kind of testing that your question implies you want to do. Either you call methods on your real class; or you specify something for a mock. But creating a mock to then "associate" it to the concrete class implementation ... is simply impossible.
Finally: if you think that your concrete class is actually "too big" to just be created the normal way for tests ... then chances are: your class is simply too big for anything else. Classes should be small; and their design should follow SOLID principles.
Long story short: don't try to force un-testable code into "tests", by using PowerMock... You better invest some more time to improve the quality of your production code; that will result in much higher "return on investment".

How to mock a final class with mockito

I have a final class, something like this:
public final class RainOnTrees{
public void startRain(){
// some code here
}
}
I am using this class in some other class like this:
public class Seasons{
RainOnTrees rain = new RainOnTrees();
public void findSeasonAndRain(){
rain.startRain();
}
}
and in my JUnit test class for Seasons.java I want to mock the RainOnTrees class. How can I do this with Mockito?
Mocking final/static classes/methods is possible with Mockito v2 only.
add this in your gradle file:
testImplementation 'org.mockito:mockito-inline:2.13.0'
This is not possible with Mockito v1, from the Mockito FAQ:
What are the limitations of Mockito
Needs java 1.5+
Cannot mock final classes
...
Mockito 2 now supports final classes and methods!
But for now that's an "incubating" feature. It requires some steps to activate it which are described in What's New in Mockito 2:
Mocking of final classes and methods is an incubating, opt-in feature. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types. As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you created this file, Mockito will automatically use this new engine and one can do :
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios. Stay tuned and please let us know what you think of this feature!
add this in your build file:
if using gradle: build.gradle
testImplementation 'org.mockito:mockito-inline:2.13.0'
if using maven: pom.xml
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>2.13.0</version>
<scope>test</scope>
</dependency>
this is a configuration to make mockito work with final classes
If you faced the Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)
Add the Byte Buddy dependency to your build.gradle file:
testImplementation 'net.bytebuddy:byte-buddy-agent:1.10.19'
src: https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy
You cannot mock a final class with Mockito, as you can't do it by yourself.
What I do, is to create a non-final class to wrap the final class and use as delegate. An example of this is TwitterFactory class, and this is my mockable class:
public class TwitterFactory {
private final twitter4j.TwitterFactory factory;
public TwitterFactory() {
factory = new twitter4j.TwitterFactory();
}
public Twitter getInstance(User user) {
return factory.getInstance(accessToken(user));
}
private AccessToken accessToken(User user) {
return new AccessToken(user.getAccessToken(), user.getAccessTokenSecret());
}
public Twitter getInstance() {
return factory.getInstance();
}
}
The disadvantage is that there is a lot of boilerplate code; the advantage is that you can add some methods that may relate to your application business (like the getInstance that is taking a user instead of an accessToken, in the above case).
In your case I would create a non-final RainOnTrees class that delegate to the final class. Or, if you can make it non-final, it would be better.
In Mockito 3 and more I have the same problem and fixed it as from this link
Mock Final Classes and Methods with Mockito
as follow
Before Mockito can be used for mocking final classes and methods, it needs to be > configured.
We need to add a text file to the project's src/test/resources/mockito-extensions directory named org.mockito.plugins.MockMaker and add a single line of text:
mock-maker-inline
Mockito checks the extensions directory for configuration files when it is loaded. This file enables the mocking of final methods and classes.
Use Powermock. This link shows, how to do it: https://github.com/jayway/powermock/wiki/MockFinal
Just to follow up. Please add this line to your gradle file:
testCompile group: 'org.mockito', name: 'mockito-inline', version: '2.8.9'
I have tried various version of mockito-core and mockito-all. Neither of them work.
I had the same problem. Since the class I was trying to mock was a simple class, I simply created an instance of it and returned that.
I guess you made it final because you want to prevent other classes from extending RainOnTrees. As Effective Java suggests (item 15), there's another way to keep a class close for extension without making it final:
Remove the final keyword;
Make its constructor private. No class will be able to extend it because it won't be able to call the super constructor;
Create a static factory method to instantiate your class.
// No more final keyword here.
public class RainOnTrees {
public static RainOnTrees newInstance() {
return new RainOnTrees();
}
private RainOnTrees() {
// Private constructor.
}
public void startRain() {
// some code here
}
}
By using this strategy, you'll be able to use Mockito and keep your class closed for extension with little boilerplate code.
Another workaround, which may apply in some cases, is to create an interface that is implemented by that final class, change the code to use the interface instead of the concrete class and then mock the interface. This lets you separate the contract (interface) from the implementation (final class). Of course, if what you want is really to bind to the final class, this will not apply.
Time saver for people who are facing the same issue (Mockito + Final Class) on Android + Kotlin. As in Kotlin classes are final by default. I found a solution in one of Google Android samples with Architecture component. Solution picked from here : https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample
Create following annotations :
/**
* This annotation allows us to open some classes for mocking purposes while they are final in
* release builds.
*/
#Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class OpenClass
/**
* Annotate a class with [OpenForTesting] if you want it to be extendable in debug builds.
*/
#OpenClass
#Target(AnnotationTarget.CLASS)
annotation class OpenForTesting
Modify your gradle file. Take example from here : https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/build.gradle
apply plugin: 'kotlin-allopen'
allOpen {
// allows mocking for classes w/o directly opening them for release builds
annotation 'com.android.example.github.testing.OpenClass'
}
Now you can annotate any class to make it open for testing :
#OpenForTesting
class RepoRepository
Actually there is one way, which I use for spying. It would work for you only if two preconditions are satisfied:
You use some kind of DI to inject an instance of final class
Final class implements an interface
Please recall Item 16 from Effective Java. You may create a wrapper (not final) and forward all call to the instance of final class:
public final class RainOnTrees implement IRainOnTrees {
#Override public void startRain() { // some code here }
}
public class RainOnTreesWrapper implement IRainOnTrees {
private IRainOnTrees delegate;
public RainOnTreesWrapper(IRainOnTrees delegate) {this.delegate = delegate;}
#Override public void startRain() { delegate.startRain(); }
}
Now not only can you mock your final class but also spy on it:
public class Seasons{
RainOnTrees rain;
public Seasons(IRainOnTrees rain) { this.rain = rain; };
public void findSeasonAndRain(){
rain.startRain();
}
}
IRainOnTrees rain = spy(new RainOnTreesWrapper(new RainOnTrees()) // or mock(IRainOnTrees.class)
doNothing().when(rain).startRain();
new Seasons(rain).findSeasonAndRain();
Give this a try:
Mockito.mock(SomeMockableType.class,AdditionalAnswers.delegatesTo(someInstanceThatIsNotMockableOrSpyable));
It worked for me. "SomeMockableType.class" is the parent class of what you want to mock or spy, and someInstanceThatIsNotMockableOrSpyable is the actual class that you want to mock or spy.
For more details have a look here
This can be done if you are using Mockito2, with the new incubating feature which supports mocking of final classes & methods.
Key points to note:
1. Create a simple file with the name “org.mockito.plugins.MockMaker” and place it in a folder named “mockito-extensions”. This folder should be made available on the classpath.
2. The content of the file created above should be a single line as given below:
mock-maker-inline
The above two steps are required in order to activate the mockito extension mechanism and use this opt-in feature.
Sample classes are as follows:-
FinalClass.java
public final class FinalClass {
public final String hello(){
System.out.println("Final class says Hello!!!");
return "0";
}
}
Foo.java
public class Foo {
public String executeFinal(FinalClass finalClass){
return finalClass.hello();
}
}
FooTest.java
public class FooTest {
#Test
public void testFinalClass(){
// Instantiate the class under test.
Foo foo = new Foo();
// Instantiate the external dependency
FinalClass realFinalClass = new FinalClass();
// Create mock object for the final class.
FinalClass mockedFinalClass = mock(FinalClass.class);
// Provide stub for mocked object.
when(mockedFinalClass.hello()).thenReturn("1");
// assert
assertEquals("0", foo.executeFinal(realFinalClass));
assertEquals("1", foo.executeFinal(mockedFinalClass));
}
}
Hope it helps.
Complete article present here mocking-the-unmockable.
Yes same problem here, we cannot mock a final class with Mockito. To be accurate, Mockito cannot mock/spy following:
final classes
anonymous classes
primitive types
But using a wrapper class seems to me a big price to pay, so get PowerMockito instead.
I think you need think more in principle. Instead you final class use his interface and mock interface instead.
For this:
public class RainOnTrees{
fun startRain():Observable<Boolean>{
// some code here
}
}
add
interface iRainOnTrees{
public void startRain():Observable<Boolean>
}
and mock you interface:
#Before
fun setUp() {
rainService= Mockito.mock(iRainOnTrees::class.java)
`when`(rainService.startRain()).thenReturn(
just(true).delay(3, TimeUnit.SECONDS)
)
}
Please look at JMockit. It has extensive documentation with a lot of examples. Here you have an example solution of your problem (to simplify I've added constructor to Seasons to inject mocked RainOnTrees instance):
package jmockitexample;
import mockit.Mocked;
import mockit.Verifications;
import mockit.integration.junit4.JMockit;
import org.junit.Test;
import org.junit.runner.RunWith;
#RunWith(JMockit.class)
public class SeasonsTest {
#Test
public void shouldStartRain(#Mocked final RainOnTrees rain) {
Seasons seasons = new Seasons(rain);
seasons.findSeasonAndRain();
new Verifications() {{
rain.startRain();
}};
}
public final class RainOnTrees {
public void startRain() {
// some code here
}
}
public class Seasons {
private final RainOnTrees rain;
public Seasons(RainOnTrees rain) {
this.rain = rain;
}
public void findSeasonAndRain() {
rain.startRain();
}
}
}
Solutions provided by RC and Luigi R. Viggiano together is possibly the best idea.
Although Mockito cannot, by design, mock final classes, the delegation approach is possible. This has its advantages:
You are not forced to change your class to non-final if that is what your API intends in the first place (final classes have their benefits).
You are testing the possibility of a decoration around your API.
In your test case, you deliberately forward the calls to the system under test. Hence, by design, your decoration does not do anything.
Hence you test can also demonstrate that the user can only decorate the API instead of extending it.
On a more subjective note:
I prefer keeping the frameworks to a minimum, which is why JUnit and Mockito are usually sufficient for me. In fact, restricting this way sometimes forces me to refactor for good as well.
If you trying to run unit-test under the test folder, the top solution is fine. Just follow it adding an extension.
But if you want to run it with android related class like context or activity which is under androidtest folder, the answer is for you.
Add these dependencies for run mockito successfully :
testImplementation 'org.mockito:mockito-core:2.24.5'
testImplementation "org.mockito:mockito-inline:2.24.5"
Mocking final classes is not supported for mockito-android as per this GitHub issue. You should use Mockk instead for this.
For both unit test and ui test, you can use Mockk with no problem.
If you need to use Mockito in an instrumented test in Android (i. e. running in an Android device), you cannot use mockito-inline. There is a special mockito-android version which doesn't solve the "final class" problem either. The only solution which seems to work is the Dexmaker library. The only limitation is that it works only in Android P (Android 9, API 28) and higher. It can be imported as follows:
androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.1"
Beware that there is also a "dexmaker-mockito" version which doesn't work for final classes either. Make sure you import "dexmaker-mockito-inline".
As others have stated, this won't work out of the box with Mockito. I would suggest using reflection to set the specific fields on the object that is being used by the code under test. If you find yourself doing this a lot, you can wrap this functionality in a library.
As an aside, if you are the one marking classes final, stop doing that. I ran across this question because I am working with an API where everything was marked final to prevent my legitimate need for extension (mocking), and I wish that the developer had not assumed that I would never need to extend the class.
For us, it was because we excluded mockito-inline from koin-test. One gradle module actually needed this and for reason only failed on release builds (debug builds in the IDE worked) :-P
For final class add below to mock and call static or non static.
1- add this in class level
#SuppressStatucInitializationFor(value ={class name with package})
2- PowerMockito.mockStatic(classname.class) will mock class
3- then use your when statement to return mock object when calling method of this class.
Enjoy
I was able to overcome this message:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class org.slf4j.impl.Log4jLoggerAdapter
Mockito cannot mock/spy because :
final or anonymous class
from this: log = spy(log);
By using this instead:
log = mock(Logger.class);
Then it works.
I guess that "default" logger adapter is an instance of a final class so I couldn't "spy" it, but I could mock the whole thing. Go figure...
This may mean that you could substitute it for some other "non final" instance if you have that handy, as well. Or a simplified version, etc. FWIW...
I am writing the steps I followed after various unsuccessful attempts to mock final/private classes and their methods in Java 11, which finally worked for me.
Create a file named org.mockito.plugins.MockMaker inside
your test/resources/mockito-extensions folder. Please create
mockito-extensions folder if not present already.
Add a single line mock-maker-inline as the content of the above org.mockito.plugins.MockMaker file
Add
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({"javax.management.*", "jdk.internal.reflect.*", "com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.*"})
#PrepareForTest(Utility.class)
annotations at the class level.
Setup process in the test class
#Before
public void setup () {
MockitoAnnotations.initMocks(this);
Mockito.mockStatic(ClassToBeMocked.class);
}
Use Mockito.when(..).thenReturn(..) for assertions
In case of multiple test cases, add the below code
#After
public void after() {
Mockito.framework().clearInlineMocks();
}
The mockito version which I am using: 3.9.0
Java version: 11
Didn't try final, but for private, using reflection remove the modifier worked ! have checked further, it doesn't work for final.

Final method mocking

I need mock some class with final method using mockito. I have wrote something like this
#Test
public void test() {
B b = mock(B.class);
doReturn("bar called").when(b).bar();
assertEquals("must be \"overrided\"", "bar called", b.bar());
//bla-bla
}
class B {
public final String bar() {
return "fail";
}
}
But it fails.
I tried some "hack" and it works.
#Test
public void hackTest() {
class NewB extends B {
public String barForTest() {
return bar();
}
}
NewB b = mock(NewB.class);
doReturn("bar called").when(b).barForTest();
assertEquals("must be \"overrided\"", "bar called", b.barForTest());
}
It works, but "smells".
So, Where is the right way?
Thanks.
From the Mockito FAQ:
What are the limitations of Mockito
Cannot mock final methods - their real behavior is executed without any exception. Mockito cannot warn you about mocking final methods so be vigilant.
There is no support for mocking final methods in Mockito.
As Jon Skeet commented you should be looking for a way to avoid the dependency on the final method. That said, there are some ways out through bytecode manipulation (e.g. with PowerMock)
A comparison between Mockito and PowerMock will explain things in detail.
You can use Powermock together with Mockito, then you do not need to subclass B.class. Just add this to the top of your test class
#RunWith(PowerMockRunner.class)
#PrepareForTest(B.class)
#PrepareForTest instructs Powermock to instrument B.class to make the final and static methods mockable. A disadvantage of this approach is that you must use PowerMockRunner which precludes use of other test runners such as the Spring test runner.
Mockito 2 now supports mocking final methods but that's an "incubating" feature. It requires some steps to activate it which are described here:
https://github.com/mockito/mockito/wiki/What's-new-in-Mockito-2#mock-the-unmockable-opt-in-mocking-of-final-classesmethods
Mockito 2.x now supports final method and final class stubbing.
From the docs:
Mocking of final classes and methods is an incubating, opt-in feature. This feature has to be explicitly activated by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you create this file you can do:
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios.
Assuming that B class is as below:
class B {
private String barValue;
public final String bar() {
return barValue;
}
public void final setBar(String barValue) {
this.barValue = barValue;
}
}
There is a better way to do this without using PowerMockito framework.
You can create a SPY for your class and can mock your final method.
Below is the way to do it:
#Test
public void test() {
B b = new B();
b.setBar("bar called") //This should the expected output:final_method_bar()
B spyB = Mockito.spy(b);
assertEquals("bar called", spyB.bar());
}
Mockito can be used to mock final classes or final methods. The problem is, this doesn't come as out of the box feature from Mockito and needs to be configured explicitely.
So, in order to do that,
Create a text file named org.mockito.plugins.MockMaker to the project's src/test/resources/mockito-extensions directory and add a single line of text as below
mock-maker-inline
Once done, you can use the mockito's when method to mock the behaviour like any other regular method.
See detailed examples here
I just did this same thing. My case was that I wanted to ensure the method didn't cause an error. But, since it's a catch/log/return method, I couldn't test for it directly without modifying the class.
I wanted to simply mock the logger I passed in. But, something about mocking the Log interface didn't seem to work, and mocking a class like SimpleLog didn't work because those methods are final.
I ended up creating an anonymous inner class extending SimpleLog that overrode the base-level log(level, string, error) method that the others all delegate to. Then the test is just waiting for a call with a level of 5.
In general, extending a class for behavior isn't really a bad idea, and might be preferable to mocking anyway if it's not too complicated.

Categories

Resources