This is a slightly esoteric questions about how public to make constructors when using an IoC container. I'm using java, Guice and Junit4, but I'm sure this question is more general.
Under Best Practices in the Guice docs, it says "Keep constructors as hidden as possible". This is something I quite agree with, so I was happy to go ahead a make my constructors private and rely on Guice for instantiation.
However, this brings up an issue with mocking classes and unit testing. If all my constructors are private, then how can I instantiate something in a unit test and pass in a mocked dependency? Having to create a new Guice module for every unit test seems like overkill to me. Surely, I must therefore actually make those constructors public.
Which brings me to the question: Given that DI is so useful when combined with unit testing, is the best practices in the Guice docs about keeping constructors hidden actually a mistake?.
Read further in the same document, which suggests giving the constructors default access. Then put your unit tests in the same package.
Default access is provided if none of public, protected or private are specified.
From the document you referenced:
As a correction, simply limit the visibility of both your implementation classes, and their constructors. Typically package private is preferred for both, as this facilitates:
binding the class within a Module in the same package
unit testing the class through means of direct instantiation
Related
I have a question.
#Autowired annotation is not recomended since Spring Boot 2.x. Then I have to use constructor.
but in during testing (JUnit 5) i don't have any warning
Questions:
that means using #Autowired during testing is good practicle ?
JUnit and Spock(which is actually based on JUnit) frameworks are enforcing tests classes to have no-args constructors only. So it's not even achievable - probably that's why you weren't prompted about potential issue.
Test classes must not be abstract and must have a single constructor.
from junit documentation
To add a bit more to this article
Additional pros for constructor autowiring:
you can validate what kind of bean is being injected, either by code or by debugging tools if something suddenly stops working as expected.
it's easier to create class instance for testing purposes, especially if it has private/protected attributes that should be mocked and you are writing tests in pure java.
field injection is not recommended for a several of concepts, most of them connected to the usage of the class in other places, e.g the class can be instantiate with the default (no-args) constructor, thus will not be created with all or any dependencies
because the actual class can be instantiate in other places like at the testing part of code you get this warning
because the testing class usually isn't meant to be instantiate at any other parts of the code, you get no warning, this doesn't mean it's ok, it's still field injection and is still not recommended
you can read more about this here
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.
Assume I have classes ClassX in production code (src/main/java) and ClassXTest in test code (src/test/java). In some test methods I want to tamper what one of the methods of ClassX returns, so I override ClassX and its method. I do not want to use any mocking frameworks or this class to be anonymous. Is there any naming how such classes should be named?
Personally, I would call these classes: ClassXTestImpl
It's not the greatest naming convention in the world, but it makes it obvious that it is test code and is not expected to be used by the production code. You could also make it a private inner class of the test class in which it is being used, then it wouldn't even be accessible by you production code.
Generally, I don't like calling things Impl, but in this case, the ClassX part will define what the class actually does and the TestImpl bit is just to mark it as a test implementation.
An aside about partial mocking:
I know you said that you didn't want to use mocking frameworks, but if you're replacing method1 in order to make method2 easier to test and both methods reside in the same class, then what you're doing is a form of partial mocking, whether you do it with a framework or not. It's difficult to find documentation for Partial Mocking that isn't linked to a particular framework, so I'll provide EasyMock's documentation but point out that most mocking frameworks support this kind of mocking.
These classes are called "test-specific subclasses" and there doesn't seem to by any naming convention. http://xunitpatterns.com/Test-Specific%20Subclass.html gives some examples of overriding classes that are under tests.
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.