Let's suppose I've to test this Java ClassA that depends on the difficult to instantiate ClassB:
public class ClassA
{
public ClassA()
{
String configFile = "config_file.xml";
// I have to pass configFile to instantiate ClassB.
// And for example if configFile does not exists in the testing machine?
// Wouldn't it be easier to have an empty constructor for classB to test ClassA?
ClassB classB = new ClassB(configFile);
}
// ...
}
ClassB:
class ClassB
{
ClassB(String configFile)
{
// Set up configs.
}
// ...
}
Is it bad practice to create an empty constructor inside classB only for testing purposes?
Or is it better to rewrite a simplified mock ClassB for that?
It seems like yours would be a suitable scenario for IoC and Dependency Injection, using something like Spring or Guice.
That way ClassA would just declare that it "needs" an instance of ClassB, and your IoC container would wire up and construct the required dependencies.
However, if you don't want to get a framework in the way, you can solve it by extracting an interface contract out of ClassB, and have ClassA depend on that, and receive a implementation to that contract in its constructor.
For example:
interface SomeContract {
void someBehavior();
}
Have ClassB implement it:
class ClassB implements SomeContract {
{
ClassB(String configFile)
{
// Set up configs.
}
void someBehavior() {
// ...
}
}
And use it, like:
public class ClassA
{
private SomeContract implementation;
public ClassA(SomeContract implementation)
{
this.implementation = implementation;
}
// ...
}
That way, in your unit test, you can pass an instance you determine in your test, such as a Mock, and you can test accordingly, without having to modify your code for ClassB.
The bottom line is, that you should try to avoid creating additional constructors and such solely for testing purposes.
Actually using parameterless constructors and creating dependencies with new keyword makes your class untestable. Since you cannot inject ClassB dependency from the constructor, you can never mock it and isolate the code under test. All of your unit tests would have to test both of the classes and that makes it a bad unit test. Instead you should add every dependency as a constructor parameter.
Here's a better approach:
public class ClassA
{
// use an abstraction instead of a concrete class
private IClassB _classB;
public ClassA(IClassB classB)
{
_classB = classB;
}
}
This way you can mock the IClassB and you don't have to worry about any ClassB implementation detail.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With