2

What is the difference between these two as per Mockito -

Mockito.when(serviceObject.myMethod(Customer.class)).thenThrow(new RuntimeException());

and

Customer customer = new Customer(); Mockito.when(serviceObject.myMethod(customer)).thenThrow(new RuntimeException());

And if both serve the same purpose then using which one is considered to be best practice?

Rito
  • 3,092
  • 2
  • 27
  • 40

2 Answers2

3

There is a misunderstanding on your side - that method specification myMethod(SomeClass.class) is only possible when the signature of that method allows for a class parameter. Like:

Whatever myMethod(Object o) {

or directly

Whatever myMethod(Class<X> clazz) {

In other words: it is not Mockito that does something special about a parameter that happens to be of class Class!

Thus your first option is not something that works "in general". Example: I put down this code in a unit test:

static class Inner {
    public int foo(String s) { return 5; }
}

@Test
public void testInner() {
    Inner mocked = mock(Inner.class);
    when(mocked.foo(Object.class)).thenReturn(4);
    System.out.println(mocked.foo(""));
}

And guess what - the above does not compile. Because foo() doesn't allow for a Class parameter. We can rewrite to

static class Inner {
    public int foo(Object o) { return 5; }
}

@Test
public void testInner() {
    Inner mocked = mock(Inner.class);
    when(mocked.foo(Object.class)).thenReturn(4);
    System.out.println(mocked.foo(""));
}

And now the above compiles - but prints 0 (zero) when invoked. Because the above would be the same as mocked.foo(eq(Object.class)). In other words: when your method signature allows for passing a Class instance and you then pass a class instance, that is a simple mocking specification for mockito. In my example: when the incoming object would be Object.class - then 4 would be returned. But the incoming object is "" - therefore the Mockito default kicks in and 0 is returned.

I am with the other answer here - I think you are mixing up that older versions of Mockito asked you to write down when(mocked.foo(any(ExpectedClass.class))) - which can nowadays be written as when(mocked.foo(any())). But when(mocked.foo(ExpectedClass.class)) is not a Mockito construct - it is a simple method specification that gives a specific object to "match on" - and that specific object happens to be an instance of class Class.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • I think I got it. In my case, I have defined `myMethod` method whose parameter type is Object. So, when I am doing `serviceObject.myMethod(Customer.class)` or `serviceObject.myMethod(CustomerDetail.class)`, Mockito is not acknowledging it. So, in this case, to make Mockito acknowledge it I have to do `serviceObject.myMethod(any())`. Just one more question, how will Mockito behave for `serviceObject.myMethod(any(Customer.class))` in this situation? Because I observe Mockito acknowledging this one also. Btw thanks a lot for this elaborate explanation, means a lot!! – Rito Sep 11 '17 at 07:37
  • Are you really **passing** class objects to your code? As said: what you have in your comment are specs that expect either a Custom or CustomerDetails class object. – GhostCat Sep 11 '17 at 07:40
  • No, the parameter type of the method is Object, but what I am passing is Customer and CustomerDetail. – Rito Sep 11 '17 at 07:42
  • A *customer* object or really Customer.class? And have you seen my updates? – GhostCat Sep 11 '17 at 07:48
  • Oh!!! Ya I am passing Customer.class. I somehow missed that update now I got it, thanks. – Rito Sep 11 '17 at 08:27
  • Sure - feel free to accept my answer(s) then at some point ;-) – GhostCat Sep 11 '17 at 08:36
2

First one which uses generic Customer class to match type can also be written as:

Mockito.when(serviceObject.myMethod(Mockito.any(Customer.class))).thenThrow(new RuntimeException());

In case of the second one, you are passing the actual object that will be used in stubbing.

Usage:

If your method myMethod throws the exception based on the state of the Customer object then you can use the latter approach, where you can set the state of the Customer object appropriately.

However If your method myMethod does not depend on the Customer object to throw the exception rather you need it only to pass it as an argument just to invoke the method, then you can take the former approach.

JavaYouth
  • 1,536
  • 7
  • 21
  • 39
  • Can you tell me what purpose `Mockito.any(Customer.class)` is serving and how is it different from `Mockito.any()`? Because what I thought the difference was, turns out it is not what it is. I thought doing `Mockito.any(Customer.class)` would mean any instance of Customer.class, but it is not what it seems like. – Rito Sep 11 '17 at 06:06
  • To understanding what I am trying to explain in my above comment please check this question - https://stackoverflow.com/questions/46149263/mockito-calling-same-method-with-different-class-paramter Here you can see that Mockito is unable to differentiate between `Mockito.any(Customer.class)` and `Mockito.any(CustomerDetail.class)`. Hope this question makes sense. – Rito Sep 11 '17 at 06:15
  • To answer your question related to usage, `myMethod` is using the instance of the `Customer` which is getting instantiated inside the Method which I want to test. So although it is based on the state of the Customer I can't do anything about it. Even if I create the same Customer instance in the test, it won't work because the reference of that will be different from the reference of the Customer instance which is created inside the testing method. – Rito Sep 11 '17 at 06:27
  • I think you are on the right track, so there goes my upvote. But I then think that the OP has simply a misconception about what he is doing there. Thus I wrote my own other to clarify that aspect ;-) – GhostCat Sep 11 '17 at 07:13