This question already has answers here:
How does mockito when() invocation work?
(2 answers)
Closed 5 years ago.
I know I don't really need to know how Mockito does everything under the hood in order to be able to use it, but this has been perplexing me for a while so more than anything I'm curious to understand it. There are several Mockito methods that I can't understand how they could possibly work. One good example is:
OngoingStubbing<T> Mockito.when(T methodCall)
You can use this to do things like:
Object mockedObject = Mockito.mock(Object.class);
Mockito.when(mockedObject.toString()).thenReturn("super cool string");
System.out.println(mockedObject.toString());
This code would give the output:
super cool string
I understand how to use this, but I don't understand how this could possibly work. How does Mockito.when know what mock object and method we are concerned with? As far as I know, we aren't passing in mockedObject, we are passing in mockedObject.toString() which is a value of type String. I'm pretty sure that prior to setting up all of the "when/thenReturn" stuff, mockedObject.toString() just returns null. So why isn't this the same as doing:
Object mockedObject = Mockito.mock(Object.class);
mockedObject.toString();
Mockito.when(null).thenReturn("super cool string");
System.out.println(mockedObject.toString());
Obviously the second code segment doesn't make any sense, but it seems like the two code segments should be functionally equivalent.
EDIT:
The two code segments actually are the same. See my answer to my own question below.
Doh!
I guess I should have actually tried to run my sample code before I posted this question.
It turns out that the two code segments actually are equivalent. I just assumed that they weren't.
This revelation sheds some light into how Mockito.when is implemented under the hood.
My best guess now, is that when mockedObject is mocked, part of the newly created implementation of Object.toString() records that the .toString() method was called (this has to be done anyway in order to get Mockito.verify() to work). It must then record this call to a mock method in some sort of thread local static variable. Then when I call when(), it actually ignores the input value (except perhaps for using its type?) and then searches for whatever mocked method was most recently called on any of the mock objects that exist in that thread (or perhaps only the method calls that match that signature). Whatever method was last called is the one that it decides to modify.
This of course just my guesses based on how I've observed mockito's functionality. The actual implementation may be different, but this at least makes sense.
Related
I've this code that no longer works after updating to Assertj 3.16.1
Throwable thrown = catchThrowable(() -> myObject.methodThrowsException());
assertThat(thrown).isInstanceOf(MyCustomException.class).extracting("fault").hasOnlyElementsOfType(CustomException.class).extracting("code").containsExactly("AnotherCustomException");
I get this error message:
java:cannot find symbol
symbol: method hasOnlyElementsOfType(java.lang.Class<CustomException.class>)
location: class org.assertj.core.api.AbstractObjectAssert<capture#1 of?, capture#2 of ?>
It's either it's deprecated or implemented differently now. I've gone through the documentation and searched this for almost two days now to see if there's any information about how to use it as opposed to how it was used previously to enable easy transition but not found anything yet. I actually get a similar error when I use this containsOnlyOnceElementsOf in place of the one giving the issue. Are there any alternatives to these methods that achieve the same thing?
Any help will be appreciated!!!
It looks like you upgraded from AssertJ 3.12 or earlier.
The error is that the AbstractObjectAssert class doesn't have a hasOnlyElementsOfType method. Moreover, it has never had that method, so it's not the case that the method was deprecated and removed. Instead, this code must have worked because hasOnlyElementsOfType was being called on some other class.
Most things in AssertJ seem to go through AbstractObjectAssert. Looking at AbstractObjectAssert in AssertJ 3.12, I see that it has a method extracting(String...) -- a varargs method -- that returns AbstractListAssert. This class in turn has a hasOnlyElementsOfType method inherited from AbstractIterableAssert. The code extracting("fault") ends up being a varargs call. This in turn returns AbstractListAssert and thus the subsequent call to hasOnlyElementsOfType works.
However, in AssertJ 3.13, AbstractObjectAssert has a new method extracting(String) -- NOT a varargs call. That method returns AbstractObjectAssert which as we've seen doesn't have the hasOnlyElementsOfType method. When compiled against this version of AssertJ (or later), the code extracting("fault") resolves to the one-arg overload. This returns AbstractObjectAssert which does NOT have the hasOnlyElementsOfType method, hence the error.
To work around this, you could force the call to extracting to call the varargs overload instead of the one-arg overload. A varargs call is just some syntax for passing an array in that position, so you could change your code to something like this:
....extracting(new String[] { "fault" })....
This ends up calling the varargs overload, which returns AbstractListAssert, which has the hasOnlyElementsOfType method that you want to call next, so things should work even in recent AssertJ versions.
As an aside, this is an example of a fairly rare case where adding a method results in an incompatibility. Usually adding methods doesn't affect any existing code. However, adding a new overload to an existing API (as AssertJ did in 3.13) potentially affects overload resolution of existing source code. That is, existing source code compiled against the old version will end up calling some method. When the same source code is compiled against the new version, it might end up calling a different method in the new API. If that new method has different behavior, it could result in subtle bugs. In this case, the new method has a different return type, so code that expected the old return type no longer works. That's exactly what happened here.
Stuart Marks has posted a great analysis, nothing to add on it, on a pure AssertJ side of things extracting(String) only extracts one value which means you can only chain object assertions instead of list assertions (makes sense as you have extracted a single value).
I believe you can do the following assertions:
assertThat(thrown).isInstanceOf(MyCustomException.class)
.extracting("fault")
.isInstanceOf(CustomException.class)
.extracting("code")
.isEqualTo("AnotherCustomException");
I need help in creating mocking two objects simultaneously.
If I set the return value of first mock obj i.e. mockClassA to null, it is working fine. I'm using annotations #Mock, #TestSubject of EasyMock. And if I don't set the first mock expectation's return as null, I'm seeing the following error.
java.lang.IllegalStateException: last method called on mock is not a void method
Here is the code, I'm trying:
EasyMock.expect(mockClassA.getValfromDB()).andReturn(ValA);
EasyMock.replay();
EasyMock.expect(mockoClassB.makeRestCall(EasyMock.anyString())).times(2).andReturn(httpResponse);
EasyMock.replay();
If EasyMock doesn't support mocking multiple objects in a single method, I'm allowed to use Mockito, PowerMockito, EasyMockSupport. Please feel free to suggest me something from those libraries too.
P.S: I already tried using replayall() from EasyMockSupport. But it didn't make any difference.
I could able to debug my code and found that I'm giving the no of times in wrong way.
Changing the line
EasyMock.expect(mockClassB.makeRestCall(EasyMock.anyString())).times(2).andReturn(httpResponse);
EasyMock.replay();
to
EasyMock.expect(mockClassB.makeRestCall(EasyMock.anyString())).andReturn(httpResponse);
EasyMock.expectLastCall().times(2);
EasyMock.replay();
has resolved my issue (Observe expectLastCall.times(2)).
Ref: TutorialsPoint.com
A mock must be passed to the replay() method. So your original code nor the answer are working. However, it is true that the times() must be after the andReturn().
So a correct code would be
expect(mockClassA.getValfromDB()).andReturn(ValA);
expect(mockClassB.makeRestCall(anyString())).andReturn(httpResponse).times(2);
replay(mockClassA, mockClassB);
or this with EasyMockSupport:
expect(mockClassA.getValfromDB()).andReturn(ValA);
expect(mockClassB.makeRestCall(anyString())).andReturn(httpResponse).times(2);
replayAll();
Note that I'm using static imports. It makes the code much more agreeable to the eyes.
I have the following code:
when(mockedOperation.getResult(anyDouble(), anyDouble())).thenCallRealMethod();
when(mockedOperation.division(anyDouble(), not(eq(0d)))).thenCallRealMethod();
Where Operation is something like Command pattern - it encapsulates some concrete action, in this case, simplified - division operation. The result retrieval happens not directly, but by the means of contract method, say getResult(arg1, arg2). So, I call
mockedOperation.division(10d, 3d);
But (from debugging info in my concrete implementation of Operation) I can see that division() gets not 10 and 3 but (0, 0).
As far as I understand, that arguments are lost somewhere between the thenCallRealMethod() by getResult() and calling real division() afterwards.
What is the reason for that behavior and how should I implement partial mocks correctly in case I really need it?
UPD. Maybe I should try to say it another way, for example, simply how do you create mocks that callRealMethod in such a way that arguments are correctly delivered to the endpoint?
OK, the problem is solved now. Turns out I just encountered another undocumented feature/bug in Mockito (or just the feature I didn't find the docs for yet). The problem was that in my #Before I also mocked that very operation, and, as it appears, when one redefines mock, something black-magical happens and the result is as I've already described - arguments are somehow lost.
I am attempting to set up a when statement for a method used inside another method I am testing. Inside the method I am testing I am creating a list which I have no reference to, therefore I cannot mock it. I would like to validate the contents of this list when it is used in the above mentioned method inside. I have used the following as part of the when method, but ended up with an "InvalidUseOfMatchersException" in every case. What am I missing?
Matchers.eq(mockKeys) //mockKeys is a List<String> with expected contents
Matchers.anyListOf(String.class)
Mockito.when(myDaoImpl.getRecords([either of the above])).thenReturn(mockResult);
I must refuse to provide exact code.
List<String> mockKeys = createMockKeys(); // defined elsewhere
when(myDaoImpl.getRecords(Matchers.eq(mockKeys))).thenReturn(mockResult);
when(myDaoImpl.getRecords(mockKeys)).thenReturn(mockResult); // implicitly equal
when(myDaoImpl.getRecords(Matchers.anyListOf(String.class)))
.thenReturn(mockResult);
All of the above are fine. Nothing you've posted looks inherently wrong; it's more likely a problem we can't see, such as if getRecords is final, or in a use of Mockito or Matchers surrounding your code. Though it is understandable not to be able to post more code than you can, it may make it hard to provide a more-specific answer.
For the sake of debugging, place a call to Mockito.validateMockitoUsage() before and after your stub. This will help ensure that the problem is actually on the line you think it is, and not pollution from calls before or after.
Your problem is the two lines Matchers.eq(mockKeys); and Matchers.anyListOf(String.class). As the message says, you're using them invalidly.
Mockito uses its own data structure to store a matcher when you call such a method, but returns a different value from the actual call. That additional value must be passed to the method that you're stubbing (getRecords in this case), and when you stub, Mockito retrieves the actual matchers from the data structure.
Unless you completely understand how the data structure works, and know exactly what you're doing, you really need to put the calls to the two Matchers methods inside the call to getRecords. For example,
when(myDaoImpl.getRecords(eq(mockKeys), anyListOf(String.class))).thenReturn(mockResult);
I'm creating a cell editor, but I've done (and seen) this in other code. I'm creating an object and then dropping it on the floor like this:
ButtonCellEditor buttonColumn = new ButtonCellEditor(table, 2);
This class takes the table and sets a TableColumnModel and custom cell renderers to it. Then, the method ends and I don't reference the buttonColumn object anymore.
So, is there a difference between doing the above and doing this (which also works)?
new ButtonCellEditor(table, 2);
Anything really wrong with doing this?
You shouldn't have unused variables in your code, that makes it less clear. Also, a constructor is (as its name states) a method for initialize the object, this in your case is not done.
I suggest you to have a static method instead:
ButtonCellEditor.niceNameHere(table, 2);
The only case I can think in which a constructor would be adequate is when it takes params to initialize itself and then perform some actions later, but not for doing the action inside and this is not like yours.
There's nothing wrong with either of those way of creating a ButtonCellEditor. However, if you later want to reference that object, with method two you have no way of doing so. With method 1 you can at least say buttonColumn.method().
No tangible difference, as far as I know.
Nothing wrong either -- I would prefer shorter form, if the only reason really is to get side effects of constructing the object (which is not necessarily a very good API design in itself, IMO, but that's irrelevant here).
There is no real difference between the two cases. In the second case an anonymous variable will be created that will be normally garbage collected. The second case will also save you some typing and is somewhat more readable. A reader may expect to find a reference at the created object (if you choose the first version) and be surprised if he doesn't find one.
In any case, a static method may be more suitable for such cases.
they are the same, but a comment about why you are doing it might be in order. otherwise someone might come along and delete it, thinking it is a no-op without investigating.
you could also be more explict and call
table.getColumn(2).setCellEditor(new ButtonCellEditor());