Getting NotAMockException on Calendar.getInstance() mocking - java

I am trying to mock Calendar.getInstance() for unit testing purpose.
I am thus using PowerMock (powermock-core:2.0.4 & powermock-module-junit4:2.0.4) and its Mockito API (powermock-api-mockito2:2.0.4).
I am well aware that similar cases do exist, but I am facing an exception that does not seem to appear on other's case.
Indeed, when doing
mockStatic(Calendar.class);
when(Calendar.getInstance()).thenReturn(aCalendar);
on a test method within a class annotated with
#RunWith(PowerMockRunner.class)
#PrepareForTest({DateUtils.class})
I get the following error : org.mockito.exceptions.misusing.NotAMockException: Argument should be a mock, but is: class java.lang.Class.
What did I do wrong and how to solve it ?
Thanks

There are a couple issues here.
mockStatic(Calendar.class); this should be in setUp method or something.
Then you do this.
verifyStatic(Calendar.class)
when(Calendar.getInstance()).thenReturn(aCalendar);
Another important thing is the following,
#RunWith(PowerMockRunner.class)
#PrepareForTest({DateUtils.class, Calendar.class})
Any class that has static method you would like to mock should be included in #PrepareForTest either at the class level or method level, if it is used only once.

Related

How to mock new instance where it return interface reference

I have a scenario like this
MyInterface myObject = new MyInterfaceImplementedClass();
myObject.get(...)
I want to mock the MyInterfaceImplementedClass, I tried like below
private MyInterface mockMyObject
private MyInterfaceImplementedClass mockMyClassObject
// the below compilation error
whenNew(MyInterfaceImplementedClass.class).withNoArguments().thenReturn(mockMyObject);
// no compilation error but not giving mocking instance at runtime
whenNew(MyInterfaceImplementedClass.class).withNoArguments().thenReturn(mockMyClassObject);
Please help me on this
Solved in the comments:
after adding my test class in side #PrepareForTest, it works as expected
In short, Mockito writes a generated subclass for the class you're trying to mock, which allows it to intercept the behavior of overridable methods (i.e. non-final instance methods). This handles all interfaces and most abstract and concrete classes. However, if you're trying to mock the behavior of final or static methods, including constructors, there's nothing Mockito can do1: the consuming class contains a reference to the exact real implementation without a lookup to the virtual method table. The only way out is to rewrite and replace the bytecode of an existing class, which is exactly what PowerMock does.
It can often just overwrite the class you're trying to mock, but in certain circumstances you need to list the class under test or the test class itself.
Consequently, almost all tests that exercise PowerMock's features require a #PrepareForTest, as well as a #RunWith statement that ensures that the test class uses PowerMock's classloader to enable that rewriting.
1 since Mockito 2.1, Mockito can use instrumented classloaders to do some of the things that were previously only available in PowerMock.

How to mock ArrayList class using using whenNew method

I'm trying to mock arraylist to verify the add method but I'm getting the message:
FAILED: testInit
Wanted but not invoked:
arrayList.add(<any>);
-> at AsyncRestTemplateAutoConfigurationTest.testInit(AsyncRestTemplateAutoConfigurationTest.java:95)
Actually, there were zero interactions with this mock.
The test class I've used is:
#Test
public void testInit() throws Exception {
ArrayList<AsyncClientHttpRequestInterceptor> interceptors = Mockito.mock(ArrayList.class);
PowerMockito.whenNew(ArrayList.class).withAnyArguments()
.thenReturn(interceptors);
Mockito.stub(interceptors.add(Mockito.any())).toReturn(true);
asyncRestTemplateAutoConfiguration.init();
Mockito.verify(interceptors).add(Mockito.any());
}
The actual tested code is:
List<AsyncClientHttpRequestInterceptor> interceptors = new ArrayList<>(interceptors);
interceptors.add(new TracingAsyncRestTemplateInterceptor(tracer));
I've declared the test class with
#RunWith(PowerMockRunner.class)
#PrepareForTest(AsyncRestTemplateAutoConfiguration.class)
Where AsyncRestTemplateAutoConfigurationis the class, which I'm using to test. Could anyone please tell me what I'm missing?
Your unit test should verify public observable behavior which is return values and communication with dependencies (which does not nessessarily imply to test only public methods).
That your production code uses an ArrayList to store your data is an implementation detail which you don't want to test since it may be changed without changing the units general behavior, in which case your unittest should not fail.
Don't start learning how to unit test using PowerMockito - it will give you bad habits.
Instead, consider working carefully through the documentation for Mockito and you will see how to structure your classes for better testing.
Ideally, your classes should be such that you do not need PowerMockito to test them and you can just rely on plain old Mockito.
If you can arrive at the point where you can write elegant and simple tests using just Mockito, it will be a sign you have grasped the fundamental concepts of unit testing.
You can start by learning how to inject dependencies through the constructor of the class that can be swapped with mocked test doubles on which behaviour can be verified.
Another point to note is, as per the other answer, the internal ArrayList in your system under test is an implementation detail. Unless consumers of your system under test can access the ArrayList through, say, methods that expose it there is not much point in writing a test against it.
If the state of the internal ArrayList affects something from the point of view of the consumer, then try writing a test against that rather than against the internal property.
Good luck with your journey on unit testing!

What happens when you use mockStatic() on a non-static class?

I'm reading some test code that calls mockStatic(MyClass.class), but MyClass is neither static nor does it contain static methods.
Are there other benefits of using mockStatic()?
Not sure if related, but PowerMock is also used in the test code.
I cannot comment so I just reply here..
According to its latest documentation, Mockito doesnt have mockStatic(), so I think this comes from PowerMock. You can go in to the method declaration to see at least the method comes from which module.
For Powermock, the class inside mockStatic() doesnt have to be static class. The goal of mockStatic is to mock the static method. See here: https://code.google.com/p/powermock/wiki/MockStatic

What is the difference between Mockito.mock(SomeClass) and the #Mock annotation?

What is the difference between Mockito.mock(Class<T> classToMock) method and the #Mock annotation?
Are they the same?
For Example, is this:
private TestClass test = Mockito.mock(TestClass.class);
the same as:
#Mock
private TestClass test;
They both achieve the same result. Using an annotation (#Mock) is usually considered "cleaner", as you don't fill up your code with boilerplate assignments that all look the same.
Note that in order to use the #Mock annotation, your test class should be annotated with #RunWith(MockitoJUnitRunner.class) or contain a call to MockitoAnnotations.initMocks(this) in its #Before method.
The difference is in the lines of code you need to write :) :) :)
Seriously though, using the annotations has the exact same effect as using the Mockito.mock.
To quote the documentation of MockitoAnnotations the use of annotations has the following benefits:
Allows shorthand creation of objects required for testing.
Minimizes repetitive mock creation code.
Makes the test class more readable.
Makes the verification error easier to read because field name is
used to identify the mock.
The javadoc for MockitoAnnotations is here
There are two significant advantages to using the annotation.
A mock created with #Mock can be injected into the class you're testing, using the #InjectMocks annotation. This is a powerful technique that can make testing significantly easier. It just won't work with mocks created by the mock method.
If you have any errors involving your mock, the name of the mock will appear in the message. If you've used #Mock, then this name will just be the name of the field. This makes it really easy to find the problem mock.
Of course, in addition to these two important advantages, most people find the #Mock notation much more readable, and it does cut down on the amount of code. I see no reason not to use it.
They both are considered same and achieve the same thing but I'd prefer the second one:
#Mock is an annotation which:
Minimizes repetitive mock creation code.
Makes the test class more readable.
Allows shorthand creation of objects required for testing.
The answer of the question is one big mistake.
We just solved some problems caused by Mockito.mock(Your.class) as a field.
We had few #Test methods. The 4th method was throwing an exception with 'thenThrow(ex)'. All of the #Test methods after it was failing and the reason was the exception thrown. They were sharing the mocked instance and the 'when' condition. After we changed from
TestClass testInstance = Mockito.mock(TestClass.class);
to
#Mock
TestClass testInstance;
everything started to work as expected. So Mockito.mock is creating a shared mock between the test methods, and #Mock does not.
In Junit5, use
#ExtendWith(MockitoExtension.class)

java.lang.IllegalStateException: incompatible return value type

I am using EasyMock to create mock classes in test cases.
expect(entity.getType()).andReturn("string");
Type belongs to the String datatype. In my development environment it is working fine. But If I transfer to my server and take build, it is failing with following error:
java.lang.IllegalStateException: incompatible return value type
I don't know why it is failing in server and getting executed in my development machine.
Development EasyMock version: 2.5.2
I just had the same problem.
I had a partial mock in EasyMock, but forgot to call addMockedMethod for the method I wanted to set the expectation for.
The error message was the same as above, I'd say that was somewhat misleading.
In my case the method was final on which I called expect on. So EasyMock was not able to mock the method and thus did not record the method invocation.
Make sure that your entity object is not a simple POJO (eg. new Entity()), and it was created with the createMock() methods of EasyMock.
For me, I had to remember to call reset(...) on it after having used it once, or I (bizarrely) got this error message calling expect on it a second time.
If anyone gets this error when trying to mock behavior of a class's toString() method, e.g. expect(entity.toString()).andReturn("string");, EasyMock will instead invoke a special version of the toString() method on that line in the test, and will not modify the expected behavior of the method in the code under test. You basically can't mock any toString() behavior, and your test will liekly still pass if you just remove the line where you're trying to mock the call. PowerMock does not seem to offer any solutions in this case, since its #PrepareForTest doesn't change this behavior.

Categories

Resources