Lesson 13 of 21
Capturing Mock Arguments
A short demo showing how you can capture the arguments sent to a mock object (external link, opens in new tab) created with Mockito.
In this lesson
Roy Osherove shows Mockito's argument captor for checking that a trace message with specific attributes was sent to the logger, by capturing the argument in a verify call and asserting on its value. He calls this clumsy and compares it with a handwritten fake (external link, opens in new tab) class, which has to change whenever a method is added to the logger interface (external link, opens in new tab). A participant suggests implementing equals on the trace message, which he says can be the most readable way when the object is simple.
Transcript
[00:03] (external link, opens in new tab) I want to show you quickly something. One of the exercises requires you to check that an a trace messages being sent to the logger with specific attributes. I want to show you how you can achieve that with Mockito. So Mockito has a special object called argument captor to capture arguments. And the way you use it is that you wait until the assert phase and then you create an argument captor of type trace message.
[00:36] (external link, opens in new tab) So you declare it and you say give me an argument captor for class trace message.class and then you do a verify but instead of just saying write message with the with an object you say write message and you send in the the the argument captor.capture. capture and then once you have that you have you can get the value from the argument by saying get me the value put it in the object back you that and one now you'll have the object that was called with the values then you can assert on the severity or on the message of the object
[01:15] (external link, opens in new tab) Now if that seems clumsy it's because it is it might be easier to write a fake (external link, opens in new tab) class of your own to just capture the argument could be just as an idea. So it would be good to experiment both with this approach and by creating a class that inherits from the slow logger or implements the logger interface (external link, opens in new tab) whichever you want. Okay, just realize that the more handwritten fake (external link, opens in new tab) classes that you have, the more you will have to change them every time you add a method to the interface of the logger.
[01:53] (external link, opens in new tab) That creates future maintainability (external link, opens in new tab). But here it definitely costs us with some readability (external link, opens in new tab). Okay, so both of these methods are not great. One of them is not great in the future. The other is not great now. But it is a trade-off. There is no good way. There is only two bad ways to do it. Okay, if you want to verify an object on the mock object (external link, opens in new tab),
[02:23] (external link, opens in new tab) That's one of the only ways to do it. Now, it could be a design issue. Maybe we don't want to do that. Maybe we we could capture things and save them as public fields. But I would venture to say that if this if we're truly tr trying to send an object, we could try to beautify this code by doing maybe helper methods (external link, opens in new tab), something like that. Extract all this into a method and say verify the call and get back the argument.
[02:53] (external link, opens in new tab) We could try to refactor this to be a bit more readable. Okay. Questions, answers. What's your answer? >> The whole equals in the fake trace message, not fake trace message. >> Yeah. Oh, yeah. Of course, that's another way. Of course, I forgot about that. You could say that you might verify
[03:28] (external link, opens in new tab) Mock log dot write message with a new trace message with severity and the message >> fails at first because the objects are not the same >> and first it fails because the objects are not the same instance. So you have to implement equals right. >> That's right source. >> Yeah. So this would actually yeah that would be a third way I completely forgot about I apologize because I am also stuck in my head about isolation frameworks.
[04:03] (external link, opens in new tab) But this would be a good way to do things if you have an object pre-prepared with all the values that you want. But you have to remember that when you do this you're basically asserting on all the attributes of the object. If you have 20 of them, you have to set up 20 of these attributes. If you do this approach, you can pick and choose which attributes you care about. So it's always a trade-off. But here, yes, if you implement equals, that might be the most readable way if the object is quite clean and simple.
[04:33] (external link, opens in new tab) >> Good. Good answer.