Is there a way to mock object construction using JMock in Java?
For example, if I have a method as such:
public Object createObject(String objectType) {
if(objectType.equals("Integer") {
return new Integer();
} else if (objectType.equals("String") {
return new String();
}
}
...is there a way to mock out the expectation of the object construction in a test method?
I'd like to be able to place expectations that certain constructors are being called, rather than having an extra bit of code to check the type (as it won't always be as convoluted and simple as my example).
So instead of:
assertTrue(a.createObject() instanceof Integer);
I could have an expectation of the certain constructor being called. Just to make it a bit cleaner, and express what is actually being tested in a more readable way.
Please excuse the simple example, the actual problem I'm working on is a bit more complicated, but having the expectation would simplify it.
For a bit more background:
I have a simple factory method, which creates wrapper objects. The objects being wrapped can require parameters which are difficult to obtain in a test class (it's pre-existing code), so it is difficult to construct them.
Perhaps closer to what I'm actually looking for is: is there a way to mock an entire class (using CGLib) in one fell swoop, without specifying every method to stub out?
So the mock is being wrapped in a constructor, so obviously methods can be called on it, is JMock capable of dynamically mocking out each method?
My guess is no, as that would be pretty complicated. But knowing I'm barking up the wrong tree is valuable too :-)
The only thing I can think of is to have the create method on at factory object, which you would than mock.
But in terms of mocking a constructor call, no. Mock objects presuppose the existence of the object, whereas a constructor presuppose that the object doesn't exist. At least in java where allocation and initialization happen together.
jmockit can do this.
See my answer in https://stackoverflow.com/questions/22697#93675
Alas, I think I'm guilty of asking the wrong question.
The simple factory I was trying to test looked something like:
public Wrapper wrapObject(Object toWrap) {
if(toWrap instanceof ClassA) {
return new Wrapper((ClassA) toWrap);
} else if (toWrap instanceof ClassB) {
return new Wrapper((ClassB) toWrap);
} // etc
else {
return null;
}
}
I was asking the question how to find if "new ClassAWrapper( )" was called because the object toWrap was hard to obtain in an isolated test. And the wrapper (if it can even be called that) is kind of weird as it uses the same class to wrap different objects, just uses different constructors[1]. I suspect that if I had asked the question a bit better, I would have quickly received the answer:
"You should mock Object toWrap to match the instances you're testing for in different test methods, and inspect the resulting Wrapper object to find the correct type is returned... and hope you're lucky enough that you don't have to mock out the world to create the different instances ;-)"
I now have an okay solution to the immediate problem, thanks!
[1] opening up the question of whether this should be refactored is well out of the scope of my current problem :-)
Are you familiar with Dependency Injection?
If no, then you ceartanly would benefit from learning about that concept. I guess the good-old Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler will serve as a good introduction.
With Dependency Injection (DI), you would have a DI container object, that is able to create all kinds of classes for you. Then your object would make use of the DI container to instanciate classes and you would mock the DI container to test that the class creates instances of expected classes.
Dependency Injection or Inversion of Control.
Alternatively, use the Abstract Factory design pattern for all the objects that you create. When you are in Unit Test mode, inject an Testing Factory which will tell you what are you creating, then include the assertion code in the Testing Factory to check the results (inversion of control).
To leave your code as clean as possible create an internal protected interface, implement the interface (your factory) with the production code as an internal class. Add a static variable type of your interface initialized to your default factory. Add static setter for the factory and you are done.
In your test code (must be in the same package, otherwise the internal interface must be public), create an anonymous or internal class with the assertion code and the test code. Then in your test, initialize the target class, assign (inject) the test factory, and run the methods of your target class.
I hope there is none.
Mocks are supposed to mock interfaces, which have no constructors... just methods.
Something seems to be amiss in your approach to testing here. Any reason why you need to test that explicit constructors are being called ?
Asserting the type of returned object seems okay for testing factory implementations. Treat createObject as a blackbox.. examine what it returns but dont micromanage how it does it. No one likes that :)
Update on the Update: Ouch! Desperate measures for desperate times eh? I'd be surprised if JMock allows that... as I said it works on interfaces.. not concrete types.
So
Either try and expend some effort on getting those pesky input objects 'instantiable' under the test harness. Go Bottom up in your approach.
If that is infeasible, manually test it out with breakpoints (I know it sucks). Then stick a "Touch it at your own risk" comment in a visible zone in the source file and move ahead. Fight another day.
Related
How do I write a mockito test for the below method? IntReqDecorate.decorate adds an Id to a call.
public class IntVisitor implements Visitor {
private final IntReqDecorator intReqDecorator;
public InternalCallVisitor() {
this.intReqDecorator = new IntReqDecorator();
}
#Override
public void apply(Call call) {
intReqDecorator.decorate(call);
}
}
You're in a bit of a bind here. Your IntVisitor class is very tightly coupled to the concrete class IntReqDecorator. And the apply method is defined, verbatim, to do the same thing as intReqDecorator.decorate. So without changing any of the signatures, the best you can possibly do is write the same test you did for decorate but over again.
Now, what you probably should do with this code is break that dependency. First, your constructor concretely builds an IntReqDecorator the moment it's constructed. You can still do that as a handy default, but you should provide a way for the caller to specify the decorator they wish to use. We can do that by overloading the constructor.
public InternalCallVisitor() {
this(new IntReqDecorator());
}
public InternalCallVisitor(IntReqDecorator intReqDecorator) {
this.intReqDecorator = intReqDecorator;
}
Now this alone is enough firepower for us to write a good test. We can mock IntReqDecorator and use the one-argument constructor in tests.
But I would go even further. You only ever use one method from IntReqDecorator, namely decorate. But since it's a concrete class, it probably has other methods that we don't really need here. So in an effort to follow dependency inversion, it may be a good idea to create an interface IntReqDecoratorLike (choose a better name for your use case) that has just that one method, and then have IntReqDecorator implement that interface.
Then your constructor takes a IntReqDecoratorLike that is capable of doing only exactly what we need it to. The great thing about this is that you barely even have to mock anything to test it. You could theoretically just write a new (ordinary) class that implements IntReqDecoratorLike and use that in tests. We'll probably still use the mocking framework, since it does provide good error messages and built-in validation, but the alternative is there in principle.
As a very broad general rule, when you find yourself scratching your head and saying "This code looks difficult to test", you should take a step back. Because oftentimes, you can make a change to the API that not only makes testing easier but also makes the code more ergonomic to use down the road.
For example, the class to be tested is
public class toBeTested {
private Object variable;
public toBeTested(){
variable = someFactory(); // What if this someFactory() sends internet request?
// Can I mock "variable" without calling
// someFactory() in testing?
}
public void doSomething(){
...
Object returnedValue = variable.someMethod(); // In testing, can I mock the behavior of
// this someMethod() method when
// "variable" is a private instance
// variable that is not injected?
Object localVariable = new SomeClass(); // Can I mock this "localVariable" in
// testing?
...
}
}
My questions are as stated in the comments above.
In short, how to mock the variables that are not injected but created inside the to-be-tested class?
Thanks in advance!
Your question is more about the design, the design of your class is wrong and it is not testable, It is not easy (and sometimes it is not possible at all) to write a unit test for a method and class that have been developed before. Actually one of the great benefit of TDD(Test Driven Development) is that it helps the developer to develop their component in a testable way.
Your class would have not been developed this way if its test had been written first. In fact one of the inevitable thing that you should do when you are writing test for your component is refactoring. So here to refactor your component to a testable component you should pass factory to your class's constructor as a parameter.
And what about localVariable:
It really depends on your situation and what you expect from your unit to do (here your unit is doSomething method). If it is a variable that you expext from your method to create as part of its task and it should be created based on some logic in method in each call, there is no problem let it be there, but if it provides some other logic to your method and can be passed as parameter to your class you can pass it as parameter to your class's cunstructor.
One more thing, be carefull when you are doing refactoring there will be many other components that use your component, you should do your refactoring step by step and you should not change the logic of your method.
To add another perspective: If faced with situations in which you have to test a given class and aren't permitted to change the class you need to test, you have the option to use a framework like PowerMock (https://github.com/powermock/powermock) that offers enhanced mocking capabilities.
But be aware that using PowerMock for the sole purpose of justifying hard to test code is not advisable. Tashkhisi's answer is by far the better general purpose approach.
Could someone please advise me on how to test a constructor using junit testing?
I have the below.
public Controller() {
view = null;
model = null;
data = null;
logger = Logger.getLogger(Controller.class);
results = Results.getInstance();
}
Nothing prevents you from calling a constructor in a JUnit test.
If your concern is with the static method calls (like Results.getInstance()), then you need to add to your test architecture something like PowerMock or JMockit.
Generally the advice would be to construct the object in your test, and then confirm that it acts correctly (getters return the right thing, etc.)
But take a step back: why do you want to test this constructor? It doesn't do anything particularly interesting or tricky (which is a good thing! Constructors usually shouldn't do much). If you construct any instances of this class, the constructor will be implicitly tested.
Usually, for constructors, I'd have a few tests that take bad input (a null arg, for instance) and confirm that the constructor throws an exception - but not much else. In your constructor's case, it doesn't have args but it does rely on the state of Results, so you should put Results into different states and then call the constructor. (Btw, that Results singleton probably isn't a great idea, in part because it makes testing trickier; you should search around for why singletons are bad.)
JUnit's site has a piece of advice that I find helpful: "test until fear [of having bugs in your code] turns to boredom." In the case of a constructor that doesn't access global state (ie, that doesn't use a singleton), that should probably be a pretty low bar.
I'm often confronted with the problem of mocking direct instantiations of classes:
final File configFile = new File(pathFile);
I'd like to mock new File(pathFile) in order to make a doReturn(otherFile).
I found that I could mock the direct instantiation by wrapping it in another method. Thing is I don't want to amend all my code by creating methods for instantiations just for unit testing, that would be ugly.
Is there any other way?
Under ideal circumstances, your method call is opaque: The only way you can influence it is to change its state, dependencies, or parameters. Constructors are inherently static method calls, which provide no opportunity (in Java) for overriding or adjusting behavior. The constructor might as well be inlined, and on some virtual machines that may literally happen.
Other than creating a testing "seam" for yourself, such as a factory object or overridable method, your only other choice is to edit the bytecode between when the class is compiled and when it is run in your test—which, incidentally, is what PowerMock does as in default locale's comment. Though PowerMock is a powerful and useful library, it does have some extremely specific installation steps that can be tricky to get right, and then you're testing the PowerMock-edited version of your class-under-test rather than the class itself.
See this answer for a related question (how to mock an instance in a private field). The specific outcome is different, but similarly you have to either refactor for testing or break encapsulation.
Is it possible to assure that only spring can instantiate a class, and not by the keyword new at compile time? (To avoid instantiating by accident)
Thank you!
If you want to detect it at compile time, the constructor must be non-public.
Private is probably too strict (it makes code analysis tools assume it will never be called, and may even cause warnings in some IDEs), I'd say the default (no modifier, package protected) is best there. In cases you want to allow subclasses in other packages (but that's impossible without allowing calling the constructor directly from that subclass) you can make it protected.
Make sure to comment the constructor appropriately, so it is clear to anyone reading the code why the constructor is like that.
Spring will call this non-public constructor without any problems (since Spring 1.1, SPR-174).
The question if this not allowing anything else to call your constructor, the idea of forcing every user of a class to use the Spring dependency injection (so the whole goal of this question) is a good idea or not, is a whole different matter though.
If this is in a library/framework (that is just usually used with Spring), limiting the way it may be used might not be such a good idea. But if it's for classes that you know will only be used in your closed project, which already forces the use of Spring, it might make sense indeed.
Alternatively, if your real goal is just to avoid the possibility of someone creating an instance and not initializing it with its dependencies, you can just use constructor dependency injection.
And if your goal is only to prevent accidental usage of the constructor (by developers not aware that the class was supposed to be initialized by Spring), but don't want to totally limit possibilities, you can make it private but also add static factory method (with an explicit name like createManuallyInitializedInstance or something like that).
Bad idea: Another possible alternative is to make the constructor publicly available, but deprecate it. This way it can still be used (without resorting to hacks like using reflection) but any accidental usage will give a warning. But this isn't really clean: it is not what deprecation is meant for.
The only obvious way I can think of doing this is at Runtime via a massive hack; Spring works with normal Java after all (i.e. anything that can be accomplished in Spring must be accomplishable via standard Java - it's therefore impossible to achieve as a compile time check). So here's the hack:
//CONSTRUCTOR
public MyClass() {
try {
throw new RuntimeException("Must be instantiated from with Spring container!");
}
catch (RuntimeException e) {
StackTraceElement[] els = e.getStackTrace();
//NOW WALK UP STACK AND re-throw if you don't find a springframework package
boolean foundSpring = false;
for (StackTraceElements el : els) {
if (el.getDeclaringClass().startsWith("org.springframework")) {
foundSpring = true; break;
}
}
if (!foundSpring) throw e;
}
}
I really would not advise doing this!
While I can understand why you would want to ensure that a class is instantiated only by Spring, this is actually not a good idea. One of the purposes of dependency injection is to be able to easily mock out a class during testing. It should be possible, then, during unit tests to manually instantiate the various dependencies and mock dependencies. Dependency injection is there to make life easier, and so it is usually good to instantiate with DI, but there are cases where using new is perfectly sensible and one should be careful not to take any design pattern or idiom to the extreme. If you are concerned that your developers are going to use new where they should use DI, the best solution for that is to establish code reviews.
I'll tell you why not to do this - you won't be able to mock your classes. And thus you won't be able to make unit-tests.
Not sure if Spring supports this as I haven't tried, and haven't used Spring in quite awhile, however with another IOC container a sneaky route I once took was to make the class one wishes to be returned as your injected interface an abstract class, and have the IOC container return that as a derived class instance. This way no-one can create an instance of the class (as it's abstract) and the container can return a derived class of this.
The container itself will generate the definition of the derived class so there's no worry of someone trying to construct one of these
Write an aspect around the call to the constructor and abort if not via Spring
don't know about spring, but if you want to have some control on creating new instances, you should make constructor private, and create public static YourClass getInstance() method inside your class which will handle checks and return new instance of that object. You can then create new class with constructor whichi will call getInstance().. and hand that class to Spring. Soon you will discover places where you had that 'illegal' calls outside spring...