2

I was trying to mock a new object creation

public class MyServiceTest {    
    MyClass myClass;
    myClass = Mockito.mock(MyClass.class);
    Mockito.when(new MyClass()).thenReturn(myClass);
}

Error:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because: 1. you stub either of: final/private/equals()/hashCode() methods. Those methods cannot be stubbed/verified. Mocking methods declared on non-public parent classes is not supported. 2. inside when() you don't call method on mock but on some other object.

I did mock the myClass object, but it is getting assigned to a new object on method call:

public class MyService {
    public static String myMethod(){
    MyClass myClass = new MyClass();
    //..........
    } 
}
alessiosavi
  • 2,753
  • 2
  • 19
  • 38
Nidheesh
  • 4,390
  • 29
  • 87
  • 150

4 Answers4

2

First: I recommend to not use PowerMock. As using this framework often results in bizarre errors, and: you have to understand that you are not facing a "deficiency" of Mockito ... but a deficiency in your design.

Basically, you want to learn about using dependency injection. The whole idea is: you do not call new within your production code. Because, you can't mock calling "new". Instead, you push the objects that your production code needs ... into your classes.

For normal (production) work, you push normal objects; and for unit testing, you push in mocked objects.

In other words: if you figure that your design would require PowerMock to be tested; then that tells you that your design needs to be reworked.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
1

This is correct behavior; Mockito doesn't support mocking new object creation. You'll need another library like PowerMock for that, or you'll need to refactor your test.

To learn a little more about each part of a Mockito-based test:

/* 1 */  MyObject myObjectMock = Mockito.mock(MyObject.class);
/* 2 */  when(myObjectMock.methodCall()).thenReturn("return value");
/* 3 */  MySystemUnderTest systemUnderTest = new MySystemUnderTest(myObjectMock);
/* 4 */  systemUnderTest.methodToTest();
/* 5 */  verify(myObjectMock).methodCalledByTheSystemUnderTest();
  1. mock creates a mock object. Note that you're not setting expectations on all instances of MyObject; instead, you're creating a single instance to control. Internally, this is actually a one-off subclass of MyObject with all its methods overridden, so Mockito is only really good for visible non-final instance methods (that you could override yourself).

  2. You can use the when call to stub behavior. The only thing that can go inside when is a single call to a method on a Mockito-created mock, so your new keyword won't work here.

  3. Again, because you can't use new, you'll generally need to insert your mock into your system under test. You (almost) never mock the system under test; you're mocking the collaborator instead, and since you can't use new you generally have to pass it in. This is part of why Mockito works so well with dependency injection systems.

  4. Then you call your method-under-test...

  5. ...and check that the final state is what you want it to be. This can be assertions like assertEquals from a test framework, calls to verify using Mockito-created mocks, or some combination of the two.

Remember, with just Mockito, you will not be able to have Java return a mock when calling new, so you'll need a step like step 3 above. Alternatively, PowerMock is an extension library on top of EasyMock or Mockito, which has static methods like whenNew and mockStatic for more advanced mocking. (A word of caution, though: Because PowerMock uses a special classloader to rewrite your classes, it can be more difficult to set up, and its magic may make your tests harder to reason about. Refactoring may be a better way to keep your tests understandable.)

Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • Added powermock and tried. `MyClass myClass; myClass = Mockito.mock(MyClass.class); whenNew(MyClass.class).withNoArguments() .thenReturn(myClass );` But still getting only the new object in `MyService.myMethod()` – Nidheesh May 03 '16 at 06:33
  • That is just me; but I would never ever recommend PowerMock to anybody; especially not to newbies. Instead, one should explain to folks how to do proper design (and DI). – GhostCat May 03 '16 at 11:12
  • @Jägermeister People are very opinionated about whether PowerMockito is worth mentioning. In [this answer](http://stackoverflow.com/q/11214136/1426891) the PowerMock answer wins over the accepted answer by over 100%. Likewise, I've tried to sternly warn about PowerMock's bytecode manipulation before, and it [went over poorly](http://stackoverflow.com/a/31522256/1426891). Suffice to say refactoring is the much better answer, but leaving out PowerMock would be incomplete anyway, and otherwise it may very well be added without explanation or warnings. – Jeff Bowman May 03 '16 at 14:43
  • @ep You've found the more-difficult setup I was describing; the pitfalls there deserve their own question and do not fit into this comment box. [The wiki goes into more detail](https://github.com/jayway/powermock/wiki/MockitoUsage), but as mentioned, refactoring your code is the better solution anyway. – Jeff Bowman May 03 '16 at 14:48
0

You can try powermock. It worked for me.

import org.powermock.api.mockito.PowerMockito;

MyClass myClassMock = Mockito.spy(new MyClass());
PowerMockito.whenNew(MyClass.class).withNoArguments().thenReturn(myClassMock);
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
AdZzZ
  • 79
  • 5
  • Gives error java.lang.NoSuchMethodError: org.powermock.reflect.internal.WhiteboxImpl.getUnmockedType(Ljava/lang/Class;)Ljava/lang/Class; – blathur Aug 08 '19 at 16:02
-1
public class MyServiceTest {    
    MyClass myClass;
    myClass = PowerMockito.mock(MyClass.class);
    PowerMockito.whenNew(MyClass.class).thenReturn(myClass);
}
Ilya Sazonov
  • 1,006
  • 10
  • 16
  • Try this! It worked for me. suggestion : Do not try to create an object with new operator in the method as this is not recommended by spring framework – MorabadBasu May 09 '21 at 11:38