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])
Related
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/
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);
}
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();
}
public Slave(Player player) {
this.party = new Party(0, null, null, null, this);
Networker.getInstance().sendString("--commandtype=system--message=setupclient--name=" + player.getPlayerName());
synchronized (this) {
this.status = State.WAITING;
}
}
I need to write a Test with JUnit 3, but i have no idea how to write one to the code above.
Because this methode sends a String to somewhere. I always get a nullpointer exception. What can I do? Im going for max code coverage
This class depends on the Networker instance. Your goal is to substitute this dependency in tests. There are several ways to do that:
Use service locator
User IoC
Mock Networker.getInstance()
Service Locator
In this case Slave shouldn't know where to get instance of Networker. It should get instance from central registry of services. This means that you need to have ServiceLocator class which basically would store link to Networker instance and you can replace it in tests.
IoC pattern
This is somewhat similar to Service Locator because Slave doesn't know where to get instance of Networker. This dependency should be provided externally (aka injected) in this case via constructor like this:
public Slave(Player player, Networker networker) {
// same as above but networker passed to method is used
}
In this case you can use another instance of networker (or mock or stub) specifically designed for your test.
Directly mock static call
Some mock frameworks allow mocking static methods. You can mock call to Networking.getInstance() so that you can check that call happened with correct parameters.
This is however not recommended and I discourage you to use this approach. See also this and this
The code Networker.getInstance() looks like you are using the singleton pattern. You are probably getting the null pointer exception because the Networker singleton has not been initialised. So Networker.getInstance() returns null, and your call to sendString fails.
It is difficult to say exactly without seeing more of the code, but it seems likely that there will be another static method in the Networker class that allows you to initialise the singleton. You could try calling that from your test case.
However, be careful that doing this doesn't result in your test sending real messages over the network!
In my experience using the singleton pattern often results in these kinds of problems when writing tests. For this reason I normally try to avoid using the singleton pattern.
You may consider trying to refactor the code to improve its design and allow you to substitute a test double for the Networker. Consider trying to replace the use of a singleton with dependency injection.
When refactoring some code I found that I had a new call which created a concrete class.
I was looking for a way to avoid the call to create a concrete class and improve testability so I created a sort of Factory which was responsible for returning me an instance. I then, using Spring constructor injection, inject the factory to the System Under Test.
However now I'm faced with a question about making the method in my factory static while at the same time having good testability. According to Misko Hevery, Static Methods are Death to testability however I do not have a clear idea what to do to remove the call to new, have good unit tests, and avoid the static method call.
This is an extract from the class that uses the factory. I am testing methods in this class that make use of the constructed (and mocked) columnFamilyTemplate:
protected AlertFieldMatcher(ColumnFamilyTemplateBuilder columnFamilyTemplateBuilder, Keyspace keyspace,
T2JsonUtilInterface jsonUtil) {
this.columnFamilyTemplate = columnFamilyTemplateBuilder.build(keyspace, CF_ALERT);
this.jsonUtil = jsonUtil;
}
And this is the factory, which I now have to mock in tests for methods in the SUT (above):
public class DefaultColumnFamilyTemplateBuilder
implements ColumnFamilyTemplateBuilder {
#Override
public ColumnFamilyTemplate<String, String> build(Keyspace keyspace,
String columnFamily) {
ColumnFamilyTemplate<String, String> builtTemplate =
new ThriftColumnFamilyTemplate<String, String>
(keyspace,
columnFamily,
StringSerializer.get(),
StringSerializer.get());
return builtTemplate;
}
...
}
The only option I see is to leave my Factory type object as is, ie not make the method static.
If you're going to remove "new" from your application, you need some mechanism for creating objects on your behalf. There are three mechanisms you might want to check out.
The first is dependency injection. DI containers allow you to take a more interface-based approach and choose what implementations to use at runtime. Spring is the most popular DI container while CDI is the new "standard". DI is fine, but it's not necessarily the kind of thing you want to introduce late in a project.
The second mechanism is the Java ServiceLoader which allows you to change implementation of components by adding and removing files from your classpath. You might find this a bit fiddly.
The last mechanism would be to use a static method (!!!!) that reads in a property which is the class name of your factory object and use Class.forName().newInstance() to create the factory object for you. This might be the simplest approach. It gives you a seam to inject a new mock factory into.
Avoiding statics is a good idea but they have their place. Use them if you understand the trade-offs involved.
You don't need to create explicitly a factory.
Extract the the creation of the new instance to a protected method in your class, exactly the same as if you were creating a factory method but providing new ThriftColumnFamilyTemplate(...) as default implementation.
In your unit tests your sut will be a partially mocked version of the class, mocking the factory method, instead of the real class. With this approach the only code untested will be the factory method, that is one single line. For the partial mocking you can use EasyMock IMockBuilder.