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/
Related
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);
}
How do you reconcile using static factory methods and mocking?
Many people would just say: Don't use static factory methods, use DI instead.
Well, sometimes you cannot avoid static factory methods. Consider the following use cases, which should be familiar:
Imagine you have a class called Option, like in scala. You can't avoid using a static factory method if you want to reuse same instance for all absent values.
As soon as you go new Option(null) you create a new option object, you cannot return the same object over and over again.
Similar use case is the Integer.valueOf() which will reuse integer objects for values below 128. Impossible to do without using a static factory method.
Another advantage is that factory methods are more descriptive than new keyword.
So how do you guys deal with having to use static factory methods and at the same time wanting to use inheritance and mocks?
Thank you.
Since it's a theorical question, I will make a theorical answer. The factory paradigm is the building point for another theory: the Injection. If your created objects are injected when needed, then you only have to inject your mocked objects to do all your tests. There alot of good books / web pages that can help you to get started on that.
Mocking out static methods is possible using PowerMock. Consider the following example from their Wiki page:
#Test
public void testRegisterService() throws Exception {
long expectedId = 42;
// We create a new instance of test class under test as usually.
ServiceRegistartor tested = new ServiceRegistartor();
// This is the way to tell PowerMock to mock all static methods of a
// given class
mockStatic(IdGenerator.class);
/*
* The static method call to IdGenerator.generateNewId() expectation.
* This is why we need PowerMock.
*/
expect(IdGenerator.generateNewId()).andReturn(expectedId);
// Note how we replay the class, not the instance!
replay(IdGenerator.class);
long actualId = tested.registerService(new Object());
// Note how we verify the class, not the instance!
verify(IdGenerator.class);
// Assert that the ID is correct
assertEquals(expectedId, actualId);
}
It's even possible to mock out only one particular method and leave the rest as is, using partial mocking.
My first option is to avoid the need to mock anything, so having static factory methods or not makes no difference.
That said, if I do want or need to mock them, then I just do it. For example, consider you are testing a JSF-based web application, and you want to mock the javax.faces.context.FacesContext object. I would write the following in a test, using the JMockit library (which I happen to develop):
#Test
public void exampleTest(#Mocked final FacesContext ctx) {
// Call the code under test, which will at some point
// call FacesContext.getCurrentInstance(), then add an
// error message for display in the web page.
new Verifications() {{
FacesMessage msg;
ctx.addMessage(null, msg = withCapture());
assertEquals("The expected error message.", msg.getSummary());
assertNotNull(msg.getDetail());
}};
}
In this example, Faces.getCurrentInstance() is the static factory method, which will automatically return a mock FacesContext instance once the class is mocked.
We simply avoid using static factory methods and we use dependency injection instead.
If java had been designed with DI in mind from the start, then Integer.valueOf() would have been:
integerType.valueOf() where integerType would be an injected dependency, or
typeSystem.getInteger().valueOf() where typeSystem would be an injected dependency, or
environment.getTypeSystem().getInteger().getFactory() where environment would be an injected dependency.
There is nothing that you can do with static factories that you cannot do with diligent use of dependency injection.
Now, once someone makes something available only via a static factory method, they are essentially coercing you to take the static road. This is unfortunate. But you can still wrap the static stuff in instances of your own device, and then inject those instances as dependencies into your production code, and then have your unit tests exercise those instances, avoiding the need to do such ungodly hacks as mocking static methods.
For example, you can wrap System.out in some StandardConsole object implementing some Console interface, and inject that Console interface as a dependency into your application.
(And if you do that, I would even add that you may proceed and configure your version control system to reject any attempts to commit code containing the string "System.out". [evil grin])
I am writing unit tests with JUnit and Mockito. Let's say I have following test class:
#Mock(name="myService")
private myServiceClass myService;
#InjectMocks
private myClassIWantToTest classUnderTest;
final myModelClass myModel = new myModelClass();
#Before
private void setUp(){
MockitoAnnotiations.initMocks(this);
}
#Test
private void testSomething(){
myModel.setCode("someCode");
final MyDataClass myData = new MyDataClass();
myData.setCode("someCode");
doReturn("someCode").when(myModel.getCode());
doReturn(myModel).when(myService.getModelByCode("someCode"));
assertEquals(classUnderTest.getDataByCode(eq("someCode")), myData);
verify(myService.getModelByCode(eq("someCode")), atLeastOnce());
}
The method getDataByCode from my classUnderTest converts the Model into Data and it should have the same code. What is a bit blurry to me is that unit tests should encapsule the classUnderTest from all dependencies. But now I have a problem. I use the setter methods myData and myModel to set a value. The thing is I put a DoReturn in there for myModel, but the problem is, that it's not a injected Mock. The method I try to test unfortunately doesn't have a field, it initializes this inside the method, so I can't really address it.
And the main thing is, when the setter of for example myModel doesn't work anymore or so, my test as shown above, wouldn't work anymore. I guess I have three questions:
How hard do I need to isolate the test class? Don't I need to use the setters for the assertEquals?
Is there another way to deal with objects, which are initialized inside a method I want to test? What is the best way to approach such a matter?
Also, what would be a good pattern for structuring this? I currently initialize my expected myData result inside a test method. The thing is that this is a rather short and easy example, but I have classes where I have tons of objects and methods.
Sounds like your main problem is the design of the class you want to test. But a few things before:
myModel.setCode("someCode");
doReturn("someCode").when(myModel.getCode());
This doesn't make sense. It's not a mock, so do...when doesn't make sense here. And if it was a mock, calling the setter would be useless.
assertEquals(classUnderTest.getDataByCode(eq("someCode")), myData);
Also strange. You want to call getDataByCode, why the eq? Do it. Call it. Write:
assertEquals(classUnderTest.getDataByCode("someCode"), myData);
Mockito-Matchers are good when you want to verify something but normally you don't use them as parameters for real method calls.
verify(myService.getModelByCode(eq("someCode")), atLeastOnce());
Does this code really compile? Shouldn't it be ...
verify(myService, atLeastOnce()).getModelByCode(eq("someCode"));
So, it would be a good idea to actually isolate your unit tests as far as you can. The less external problems you are inviting into your test, the better the test can be.
The method I try to test unfortunately doesn't have a field, it
initializes this inside the method, so I can't really address it.
This simply sounds like a code smell, but without the actual code in question, it's hard to say...
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.
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.