PowerMockito: how to mock methods called by the constructor? - java

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.

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/

Limitations of Mockito

I know that Mockito doesn't support mocking of local variables, static methods and private methods. Is there any way to get around it.
Like in the case of private methods changing the method from private will do or we could change it to a protected interface so that we could write test scripts. So do we have anything like this for static methods and local variables.
https://github.com/mockito/mockito/wiki/FAQ says the limitations of Mockito. Can any Mockito guru let me if it got any other limitations and how to overcome them I mean by refactoring. Thank you.
The best way to avoid the limitations of Mockito is to not insist on writing isolated unit tests.
Contrary to what some think, unit tests do not need to run in isolation from the dependencies of the tested unit. As described by Martin Fowler (and as practiced by Kent Beck, the "father" of TDD), unit tests can be "sociable" (with no mocking of dependencies) or "solitary" (with mocked dependencies).
So, one way to avoid those mocking tool limitations is to simply not rely on them. You can do that by writing "sociable" unit tests, or (like I do) go the whole way and write integration tests.
The other "solution" that was mentioned is to refactor the code under test in order to work around mocking limitations, or to "design for mocking" (as Jeff Bowman said).
I hope most developers realize this is a bad solution, as it usually requires adding extra complexity to the SUT, just to make up for arbitrary limitations in a particular mocking library.
Consider the case of increasing the accessibility of a private method so you can test it directly or mock it. Well, if you find that acceptable, do you really care about code quality? And if you don't care, then why bother with automated developer testing anyway?
To help understand Mockito's limitations, it's important to realize what Mockito is doing for you: Mockito creates a dynamic (proxy-based) subclass of the class you pass in. This means that, like a subclass you would write yourself, you won't have access or control over private fields and methods, static methods, and local variables. There is no workaround.
You mentioned PowerMock in the comments, which works around some of the Mockito limitations by rewriting the bytecode of the class you want to mock, or the class that consumes a class you want to mock. This allows PowerMock to intercept calls that you can't override via polymorphism, particularly private, static, and final fields. You also won't have access to local variables.
Your best bet is, instead, to restructure your class or method so that it does give you the control you want. In general you should be asking "would I be able to do this if I created my own subclass", and that answer will help determine whether Mockito can automate it for you.
(Note that below I've referred to "designed for mocking", but what you're really doing is designing for alternative implementations of your dependencies; mocks are just one example of this, along with a variety of other test doubles like fake or in-memory implementations. Remember that not everything needs to be mocked or substituted for your test to remain a unit test; just make sure your dependencies in tests are fast, deterministic, and well-tested. Conversely, for slow, nondeterministic, poorly-tested, or yet-unwritten components, substituting an implementation with a fake or mock may improve test quality and coverage.)
public class NotDesignedForMocking {
public int yourMethod() {
Calculator calculator = new Calculator(); // impossible to mock!
return calculator.calculate();
}
}
One technique is to pass in your dependency as a method parameter.
public class DesignedForMockingViaMethodLevelDependencyInjection {
public int yourMethod() {
return yourMethod(new Calculator());
}
// Call this from tests instead; you can pass in a mock.
int yourMethod(Calculator calculator) {
return calculator.calculate();
}
}
Another is to switch to full dependency injection:
public class DesignedForMockingViaFullDependencyInjection {
private final Calculator calculator;
public DesignedForMockingViaFullDependencyInjection() {
this(new Calculator());
}
// Create objects in your test with this, so you can pass in a mock Calculator.
DesignedForMockingViaFullDependencyInjection(Calculator calculator) {
this.calculator = calculator;
}
int yourMethod() {
return calculator.calculate();
}
}
Finally, you can create an overridable factory method, which introduces the polymorphism that Mockito needs for its subclass-based overrides.
public class DesignedForMockingWithOverridableFactoryMethod {
public int yourMethod() {
Calculator calculator = createCalculator();
return calculator.calculate();
}
// Create an anonymous override in your class, or use a Mockito spy to intercept
// and override the behavior.
protected Calculator createCalculator() {
return new Calculator();
}
}
See also: How to use Mockito when we cannot pass a mock object to an instance of a class

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);
}

Passing mocked static method to another class

I have mocked a static method of a class using Powermock in my test class. The problem I face is that this static method is not called directly in my test class, but in some other class. Here is the skeleton:
#Test public void myTest() {
PowerMockito.mockStatic(MyClassWithStaticMethod.class);
PowerMockito.when(MyClassWithStaticMethod.staticMethod()).thenReturn("...");
List<String> details = MyHelperClass.getDetails();
...
...
}
Now MyHelperClass.getDetails calls the method that needs to be mocked as it is dependent upon a service.
MyHelperClass.java
public static List<String> getDetails() {
...
...
MyObj obj = MyClassWithStaticMethod.staticMethod(); //This needs to return mocked value
...
...
}
Is there a way to pass the mocked object to the helper class? PowerMockito.mockStatic returns void, where as PowerMockito.mock doesn't mock the static methods. So I am not able to figure out how to pass the mocked object to the helper class getDetails() method.
PowerMock isn't really capable of what you're willing to achieve. There's another mocking framework, that can mock literally almost everything by instrumenting the bytecode - JMockit
As for your problem - perhaps that would help
Just a simple note regarding static methods - since this kind of methods is harder to stub and since stubbing them can potentially affect other tests, I recommend adding unit tests for them and relying on those tests instead of trying to make sure the method is called.
The reason I'm advocating on this approach is that static methods should consist only of utility methods, which once tested can be relied upon. And also checking method calls always introduces coupling between your code and the unit tests, resulting in headaches when thinking about refactoring, as application code refactoring leads to lots of unit tests needing changes.

How does Mockito spy mock internal method calls?

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? :) ]

Categories

Resources