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.
Related
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.
I have some problems with unit testing the following method.
public List<GetSupplyChainResponse> getSupplyChains(){
List<GetSupplyChainsResponse> response = new ArrayList<>();
supplyChainRepository.findSupplyChainsWithCompound().forEach(result
-> response.add(getGetSupplyChainSimpleResponse(result)));
return response;
}
getGetSupplyChainSimpleResponse() is a private method of the same class as getSupplyChains()
Is there any possibility to define return values therefore or do you have any other ideas how I could test the method getSupplyChains()?
You might be overthinking this. The fact that the method that you want to test (getSupplyChains) uses a lambda that calls a private method is irrelevant: they are just implementation details.
What you unit test is the part of your class that you as a client interact with, i.e. its interface. You typically call a public method with some arguments (in this case there are none), you get some return value and that is what you verify in your unit test. If your public method makes use of some private method, it will be tested also.
The problem here is that the response that you get from getSupplyChains obviously depends on what supplyChainRepository.findSupplyChainsWithCompound() returns. What you do in this case is mock that dependency (supplyChainRepository) out: you create a mock instance of SupplyChainRepository, you tell it how to behave, and you pass it to this class, for example via the constructor.
You can either write the mock yourself, or you can rely on a mocking framework to do the heavy lifting like Mockito.
I definitely recommend against unit testing private methods (it leads to brittle tests), or increasing the visibility of those methods (a.k.a. sacrificing your design for the sake of testing).
It is a commonly discussed problem, some prefer using reflection as Janos Binder recommended (How to call a private method from outside a java class), some can live with the fact the the visibility of the methods which we need to mock is increased for the sake of testability.
The problem is quite well discussed here: How do I test a class that has private methods, fields or inner classes?. You can see from the answers and wide discussions that the topic is quite complicated and developers split into factions and use different solutions.
I'd recommend you to remove the private access modifier and to make the method package private (use the default visibility). The common custom is to have the test classes in the same package (but not in the same folder!) as the tested classes.
This will allow you to:
Test the getGetSupplyChainSimpleResponse() method itself, which you should do in any case somehow.
Mock its behaviour for the purpose of testing getSupplyChains(). This you will achieve e.g. by using Mockito framework and its #Spy functionality.
For those who argue that this is "sacrificing your design for the sake of testing", I would answer that if you have private methods which need to be mocked and/or tested, then the design is not ideal anyway so changing the visibility to package private does not mean too big deterioration. The clear solution (from the object oriented design's point of view) is to delegate the behavior of such private methods to separate classes. However, sometimes in the real life it is just overkill.
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.
Can anyone please summarize, what exactly features gives you adding PowerMock on top of the Mockito?
So far I've found these:
mock static, final and private methods
remove static initializers
allow mocking without dependency injection - this one isn't clear to me. Can you elaborate?
Does it add anything else? Can you please sum up in several lines?
And do I need to sacrifice something when using PowerMock?
I don't know of other benefits offhand, but I want to address 2 of your sub-questions (and this is way too long for a comment):
allow mocking without dependency injection - this one isn't clear to me. Can you elaborate?
I think this came from the Motivation wiki page where they describe a way of refactoring code to not invoke static methods to make it testable. For a concrete example of what I think they're getting at, let's say you have this code and you want to test the method mocking the behaviour of the static method, without using powermock:
public class MyClass {
public void doGetString() {
...
OtherClass.getString(); //It's complex and scary and needs mocking!
...
}
}
One solution, would be to pull the static invocation into its own object, then inject an object that can be mocked come test time. For example, without using other frameworks, this could look like:
public class MyClass {
public static class StringGetter {
public getString() {
return OtherClass.getString();
}
}
private final StringGetter getter;
//Existing Constructor
public MyClass() {
this(new StringGetter());
}
//DI Constructor
MyClass(StringGetter getter) {
this.getter = getter;
}
public void doGetString() {
...
getter.getString();
...
}
}
I've seperated the behaviour of my method from the behaviour of the static invocation, and can use the DI constructor to inject mocks easily at test time. Of course with powermock I could just mock the static method in place, and run with it.
And do I need to sacrifice something when using PowerMock?
Physically no, but I'd say philosophically yes :). The below are my opinions, and I try to give good reasons behind them, but of course they are opinions so take them with a grain of salt:
The potentially scary thing that is happening with PowerMock is that in order to accomplish the feats of mocking private and static methods, they are using a custom class loader (which shouldn't be present at runtime in production) and changing the bytecode of your classes. Arguably, this should not matter with the vast majority of classes most of the time, but if you think about it, if the bytecode has changed, and certain side effects are no longer present, you're effectively testing different Classes albiet based upon your existing Classes. Yes this is a very academic argument.
You can somewhat mitigate this first argument by having good comprehensive integration and higher level tests that don't use PowerMock. In this way you can be more confident in the behaviours of your objects even if your unit tests are using PowerMock.
The other argument I have against PowerMock, is that it could almost too easily become a crutch. I agree that PowerMock can help with testing code that uses legacy code and other code that you do not have control over. However I would argue that when you have control over the classes that you need to mock, you should avoid its use. If you write a class with a private method or static method that you need to explicitly mock in order to test other methods, my gut instinct would say that this method may be doing too much and should be refactored and broken up. Having PowerMock already available in a project, you may be tempted to just mock it and move on, which would mitigate the pain that should encourage you to refactor the same. Yes there are sometimes due to various technical and non-technical constraints this is not possible, but it's good to solve pain points instead of avoid them :)
PowerMock is an extension to Mockito that allows mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more.
Another feature of the Powermock mockito extension is that it supports mocking and stubbing of equals and hashcode.
As with all powermock features to be used with care, but adding (value-based) equality for specific results can be helpful.
One more feature of PowerMock is that we can mock construction of new objects in a method. It is helpful when we cannot change the code of the method to be tested.
For mocking final class we can use org.mockito.plugins.MockMaker. What you would need to do is
Create a folder in your test/resource folder with namemockito-extensions.
Create a file under it with the name org.mockito.plugins.MockMaker.
In that file have just one line mock-maker-inline
This will not require you to do add any new library and hence save some runtime.
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.