Mockito: Mock and inject a mocked class - java

I currently am faced with the following test case:
I want to mock the abstract ActorRef class from akka:
#RunWith(MockitoJUnitRunner.class)
public class ConstraintBuilderTest {
#Mock
ClassANeededByClassB a;
#InjectMock
ClassB b;
#Before
public void setUp(){
Mockito.when(a.equals(a)).thenReturn(true);
}
//tests go here
}
I know that the mockito page says it cannot mock equals. So are there any ideas on how to mock that?
The equals method on ClassB uses ClassANeededByClassB to check its equality.
What I could think of to do is to inject a into the mocked class b. How best to proceed?
Please be aware that the classes come from a framework which I cannot change, so I cannot change its code to add a setter or anything like that.

b is a mock, so you shouldn't need to inject anything. After all it isn't executing any real methods (unless you explicitly do so with by calling thenCallRealMethod), so there is no need to inject any implementation of ClassANeededByClassB.
If ClassB is the class under test or a spy, then you need to use the #InjectMocks annotation which will inject any matching mocks into ClassB.
#RunWith(MockitoJUnitRunner.class)
public class ConstraintBuilderTest {
#Mock
ClassANeededByClassB a;
#InjectMocks
ClassB b;
// ...
}
As you said, Mockito doesn't support mocking equals. There might be some workarounds but I don't know any. So here's just some thoughts about it in general:
Mockito's approach is that if you can't mock something with Mockito, it probably is badly designed and should be refactored. I know it's not your code, and that actually leads to the next point:
"Don't test the framework". You likely don't need to test this part at all - it should be the responsibility of the frameworks creators to test it. You could try to contribute a patch if it is an open source project.
Mockito has some self-imposed limitations, so it might just not be the right tool for this job. There are other mocking frameworks that are more powerful and capable of doing this.

Related

What constructor is being called (if any) for a mocked class in Mockito?

When in a test class we instruct mockito to providing some mock objects (annotating such attribute-fields with #Mock) for the purpose of the testing (maybe to be injected into #InjectMocks attribute-field), what are the rules being followed for creating each mock?
More specifically:
1) how is each mock being built?
2) how are the dependencies of each mock being handled? what rules and limitations should be considered when mocking?
3) The case "mocked class A depends on class B, and class B is in turn mocked (in the same test class)" is different from the case "mocked class A depends on class B and class B is not mocked"?
The idea of mocks is exactly the opposite of what your question implies: they are not called by calling your constructors. That is the whole idea of mocks: they have nothing to do with your production code.
In other words: you ask for a mock object of some A.class; and you get an object that supports the methods of A.class. In that sense, a mocked A object doesn't have any dependencies.
You know, that is the whole point: if a mocked A would be the same as a real A; what sense would be in mocking?

Mock is not applied on new object creation

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();
//..........
}
}
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.
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();
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).
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.
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.
Then you call your method-under-test...
...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.)
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);
public class MyServiceTest {
MyClass myClass;
myClass = PowerMockito.mock(MyClass.class);
PowerMockito.whenNew(MyClass.class).thenReturn(myClass);
}

Mockito method call without object

The code has something like
Speed speed = readSpeed(Point A, Point B);
isOverLimit = limitCheck.speedCheck(speed);
How do I use mockito for read speed?
Mockito.when(readSpeed(0, 0).then...
suppose should I use the class object to call this?
Mockito effectively works by creating individual subclasses of objects that delegate every overridable implementation to the mock framework.
Consequently, you can't use Mockito mock your method (readSpeed) for all instances at once or instances created in your system under test, nor mock any static or final methods. If readSpeed is any of those, or need to be mocked on an instance you don't touch in your test, Mockito will not work for you; you'll need to refactor, or use PowerMockito (which quietly rewrites your system under test to redirect constructors, final calls, and static calls to Mockito's framework).
If readSpeed is a public non-final instance method on your system under test, then you can mock it, and that'd be called a partial mock of your component. Partial mocks can be useful, but can also be considered "code smells" (as mentioned in the Mockito documentation): Ideally your test class should be an atomic unit to test, and mocking should happen for the dependencies around your system under test rather than your test itself. Otherwise, you could too easily test the spec or test the mocking framework rather than testing your component.
Though the better thing to do would be to split the class into smaller interconnected components, you can use partial mocking in Mockito like this:
#Test public void componentChecksSpeed() {
YourComponent yourComponent = Mockito.spy(new YourComponent());
// Use doReturn, because the when syntax would actually invoke readSpeed.
doReturn(65).when(yourComponent).readSpeed(any(Point.class), any(Point.class));
yourComponent.run();
}

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)

PowerMockito: how to mock methods called by the constructor?

I have the following class:
public class Foo {
public Foo() {
initField1();
initField2();
initField3();
}
}
I need to change the behaviour (to mock) initField1() and initField3() for them making do nothing or something else that they actually do. I am interested in executing the actual code of initField2().
I want to write the following test:
Foo foo = new Foo();
assertTrue(foo.myGet());
myGet() returns an attribute of Foo that has been computed by initField2().
The initField() methods are of course private.
How can I do such a thing?
Thanks for your help and best regards.
Considering anything can happen in legacy code :) you can use PowerMock to supress methods as described in http://code.google.com/p/powermock/wiki/SuppressUnwantedBehavior
import static org.powermock.api.support.membermodification.MemberMatcher.methods;
import static org.powermock.api.support.membermodification.MemberModifier.suppress;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Foo.class)
public class FooTest {
#Test
public void testSuppressMethod() throws Exception {
suppress(methods(Foo.class, "initField1", "initField3"));
Foo foo = new Foo();
}
}
Still, you should re-factor the class after you've got adequate test coverage for it.
I think there is something wrong in what you want to do.
As far as I understand, a mocking framework such as Mockito or PowerMock is meant to mock interaction between the object under test and its dependencies.
As I understand your question, you want to mock part of the object behavior, and test the rest of it.
In your case, you want to test something that will never happen, as initField2() will never be called without calls to initField1() and initField3()
If the reason you don't want to call initField1() and initField3 is because these methods interact with other objects, or filesystem or DB, then you should rather inject the dependencies via constructor argument or annotated setters, and just inject mocks for your tests. And to instantiate your object with its dependencies properly set up, use the factory pattern, the builder pattern, or even better, use a dependency injection framework such as the one from Spring or Google Guice.
If the reason you d'ont want to call initField1() and initField3 is because they deal with different business logic in your object, then this smells (as in http://martinfowler.com/books/refactoring.html) like you're breaking the single responsibility principle, and you should refactor.

Categories

Resources