How does Mockito spy mock internal method calls? - java

I always thought Mockito works some some kind of proxy and things like that. But now I found out, that Mockito allows me to do something like
class A {
public String m1() {
return m2();
}
public String m2() {
return "Hello";
}
}
class TestA {
public testM1() {
A a = Mockito.spy(A.class);
when(a.m2()).thenReturn("Bye");
Assert.assertEquals(a.m1(), "Bye");
}
}
This wouldn't work with proxies. How does it do this?
Could that technique be used to allow calling internal AOP-methods? (see Spring AOP not working for method call inside another method)

Mockito does work with proxies, and does support spies. Your syntax is a bit off, though:
/* BAD */ A a = Mockito.spy(A.class);
/* GOOD */ A a = Mockito.spy(new A());
The reason for the different behavior is that a doesn't delegate to the parameter to spy(), but instead copies the field values to a brand new generated subclass of A with all of its methods overridden. Consequently, in Spring, references to this from within A refer to the unwrapped instance, where in Mockito references to this refer to the wrapped object—including the implicit reference to this in the m2() call within m1.
Though this sounds like it would allow for use of AOP, I'm not in a position to test that it works, and believe it would depend on the implementation details of Mockito and Spring AOP (and the order in which the wrapping happens).
[Editorial: Even if you can get the two code-generating systems to work well together, will you and your coworkers be able to read/understand/debug the test a year from now? :) ]

Related

Mockito, mocking a constructor within a method of a class

Currently trying to write unit tests for a complicated system that uses a constructor within one of its method that takes itself as the parameter to inject into a database context and retrieve the correct object from the correct environment.
Trying to use Mockito to emulate this, and make it return a test object instead of it going to try and find it from the database; but i'm stumped as to how to make it work with traditional techniques and #InjectMocks + #Mock annotations.
The essence of the code is below:
public FooService{
public String fooFindObject(FooDefinition fooDef) throws FooDefinitionException{
FooFinder theFooFinders = new FooFinder(this);
Foo fooObj = theFooFinders.findFoo(fooDef);
//Logic to be tested inside here that will throw exception upon bad foo definitions
return fooObj.trackingId();
}
How could I mock this FooFinder object and make it return my own testing foo object so I can test the definition obj. Mockito is being used, and the possiblity of rewriting this code to use get/setters of the FooFinder obj is not allowed - it's not my code and I'm just there to test it.
There is a library that extends upon Mockito: PowerMockito.
It allows you to do quite some more hacking than the usual Mockito. It's pretty sweet, but the thing is, if you need PowerMockito, your design usually smells.
I would definetely refactor your design. But if you can't do this for any reason, please take a look at constructor mocking with PowerMockito:
http://benkiefer.com/blog/2013/04/23/powermockito-constructor-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);
}

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.

Unit test for method that calls multiple other methods using Mockito

Perhaps I have completely fallen short in my search, but I cannot locate any documentation or discussions related to how to write a unit test for a Java class/method that in turn calls other non-private methods. Seemingly, Mockito takes the position that there is perhaps something wrong with the design (not truly OO) if a spy has to be used in order to test a method where mocking internal method calls is necessary. I'm not certain this is always true. But using a spy seems to be the only way to accomplish this. For example, why could you not have a "wrapper" style method that in turn relies on other methods for primitive functionality but additionally provides functionality, error handling, logging, or different branches dependent on results of the other methods, etc.?
So my question is two-fold:
Is it poorly designed and implemented code to have a method that internally calls other methods?
What is the best practice and/or approach in writing a unit test for such a method (assuming it is itself a good idea) if one has chosen Mockito as their mocking framework?
This might be a difficult request, but I would prefer for those who decide to answer to not merely re-publish the Mockito verbiage and/or stance on spies as I already am aware of that approach and ideology. Also, I've used Powermockito as well. To me, the issue here is that Mockito developed this framework where additional workarounds had to be created to support this need. So I suppose the question I am wanting an answer to is if spies are "bad", and Powermockito were not available, how is one supposed to unit test a method that calls other non-private methods?
Is it poorly designed and implemented code to have a method that internally calls other methods?
Not really. But I'd say that, in this situation, the method that calls the others should be tested as if the others where not already tested separately.
That is, it protects you from situations where your public methods stops calling the other ones without you noticing it.
Yes, it makes for (sometimes) a lot of test code. I believe that this is the point: the pain in writing the tests is a good clue that you might want to consider extracting those sub-methods into a separate class.
If I can live with those tests, then I consider that the sub-methods are not to be extracted yet.
What is the best practice and/or approach in writing a unit test for such a method (assuming it is itself a good idea) if one has chosen Mockito as their mocking framework?
I'd do something like that:
public class Blah {
public int publicMethod() {
return innerMethod();
}
int innerMethod() {
return 0;
}
}
public class BlahTest {
#Test
public void blah() throws Exception {
Blah spy = spy(new Blah());
doReturn(1).when(spy).innerMethod();
assertThat(spy.publicMethod()).isEqualTo(1);
}
}
To me, this question relates strongly to the concept of cohesion.
My answer would be:
It is ok to have methods (public) that call other methods (private) in a class, in fact very often that is what I think of as good code. There is a caveat to this however in that your class should still be strongly cohesive. To me that means the 'state' of your class should be well defined, and the methods (think behaviours) of your class should be involved in changing your classes state in predictable ways.
Is this the case with what you are trying to test? If not, you may be looking at one class when you should be looking at two (or more).
What are the state variables of the class you're trying to test?
You might find that after considering the answers to these types of questions, your code becomes much easier to test in the way you think it should be.
If you really need (or want) to avoid calling the lower-level methods again, you can stub them out instead of mocking them. For example, if method A calls B and C, you can do this:
MyClass classUnderTest = new MyClass() {
#Override
public boolean B() {return true;}
#Override
public int C() {return 0;}
};
doOtherCommonSetUp(classUnderTest);
String result = classUnderTest.A("whatever");
assertEquals("whatIWant", result);
I've used this quite a quite a bit with legacy code where extensive refactoring could easily lead to the software version of shipwright's disease: Isolate something difficult to test into a small method, and then stub that out.
But if the methods being called are fairly innocuous and don't requiring mocking, I just let them be called again without worrying that I am covering every path within them.
The real question should be:
What do I really want to test?
And actually the answer should be:
The behaviour of my object in response to outside changes
That is, depending on the way one can interact with your object, you want to test every possible single scenario in a single test. This way, you can make sure that your class reacts according to your expectations depending on the scenario you're providing your test with.
Is it poorly designed and implemented code to have a method that internally calls other methods?
Not really, and really not! These so called private methods that are called from public members are namely helper methods. It is totally correct to have helper methods!
Helper methods are there to help break some more complex behaviours into smaller pieces of reusable code from within the class itself. Only it knows how it should behave and return the state accordingly through the public members of your class.
It is unrare to see a class with helper methods and normally they are necessary to adopt an internal behaviour for which the class shouldn't react from the outside world.
What is the best practice and/or approach in writing a unit test for such a method (assuming it is itself a good idea) if one has chosen Mockito as their mocking framework?
In my humble opinion, you don't test those methods. They get tested when the public members are tested through the state that you expect out of your object upon a public member call. For example, using the MVP pattern, if you want to test user authentication, you shall not test every private methods, since private methods might as well call other public methods from an object on which depend the object under test and so forth. Instead, testing your view:
#TestFixture
public class TestView {
#Test
public void test() {
// arrange
string expected = "Invalid login or password";
string login = "SomeLogin";
string password = "SomePassword";
// act
viewUnderTest.Connect(login, password);
string actual = viewUnderTest.getErrorMessage;
// assert
assertEqual(expected, actual);
}
}
This test method describes the expected behaviour of your view once the, let's say, connectButton is clicked. If the ErrorMessage property doesn't contain the expected value, this means that either your view or presenter doesn't behave as expected. You might check whether the presenter subscribed to your view's Connect event, or if your presenter sets the right error message, etc.
The fact is that you never need to test whatever is going on in your private methods, as you shall adjust and bring corrections on debug, which in turn causes you to test the behaviour of your internal methods simultaneously, but no special test method should be written expressly for those helper method.

Automatic stubbing in java word. What to use?

I have huge class that I need to build stub for.
To give you picture it is Messages class of the GWT. Often this is class with dozens of methods that return String.
With JMock I can do stubbing, but I will end with allowing each method... This is not something that I would like to see.
Is there something that will automatically build the stubs for each method? I need this methods to return something predefined, like empty string, but I will be happy with any suggestions.
In JMock you can allow the methods you care about with explicit results and then allow any other method of the messages object with an allowing statement that does not include a method. E.g.:
allowing(m).getBlah("something");
will(returnValue("foo"));
allowing(m); // matches anything else, will return some default value if called
But...
If you are just stubbing a bunch of getter methods, a mock object framework is the wrong tool to use. Mock objects are used for testing that the object under test sends the correct commands to neighbouring objects to effect change in its environment.
It's often easier to create a stub class if the interface that only contains getters. Or you can use Usurper to generate stubs automatically.
For an interface you can use the functionality of java.lang.reflect.Proxy. Assuming that you want to stub answers for the MessageConstants class, the code will look similar to:
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (String.class.equals(method.getReturnType()))
return "proxy generated method return";
throw new AbstractMethodError("Not implemented");
}
};
Class<?> proxyClass = Proxy.getProxyClass(MessageConstants.class.getClassLoader(), new Class[] { MessageConstants.class });
MessageConstants messageConstants = (MessageConstants) proxyClass.getConstructor(new Class[] {InvocationHandler.class}).newInstance(new Object[] { handler });
System.out.println(messageConstants.description());
messageConstants.getBoolean("someBoolean");
and will result in
proxy generated method return
Exception in thread "main" java.lang.Error: Not implemented
at xxx.Application$1.invoke(Application.java:48)
at $Proxy0.getBoolean(Unknown Source)
at xxx.Application.main(Application.java:64)
The InvocationHandler drives the stubbing, while the rest is just plumbing.
Glad to see you found an answer. Just for further info, jMock allows quite flexible specifications of how you match methods, see http://www.jmock.org/match-object-or-method.html. For example, you can do this sort of thing:
allowing (any(Object.class)).method("get.*").withNoArguments();
to match any getter.
S
If you use EasyMock, you only need to specify behavior/expectations/stubs for the methods you actually expect to be called and used.
After using both JMock and EasyMock, I have to say that EasyMock's API is about 10x easier to use, and since the interface is mostly statically-typed, it's refactoring safe as well (you are using Strings for method names, etc.).

Categories

Resources