I am trying to unit test two separate classes, the constructor of one being the default constructor and the constructor of another, a constructor having some arguments. Both the classes have an autowired component, say,
class A {
@Autowired
private SomeClass someClass;
}
class B {
@Autowired
private SomeClass someClass;
public B(int a, String b) {
//method implementation
}
}
I am trying to unit test these two classes and for the first one if I create the class object using
def mockedSomeClass = Mock(SomeClass)
def a = new A(someClass:mockedSomeClass)
it works fine.
But for the second class , I have tried passing the constructor arguments and the dependencies required through different syntaxes
like
def mockedSomeClass = Mock(SomeClass)
def b = new B(10, "g", someClass:mockedSomeClass)
and
def b = new B(someClass:mockedSomeClass, 10, "g")
and
def b = new B(10, "g")(someClass:mockedSomeClass)
All these were trial and error as I could not find any documentation similar to this particular case.
Any help on how to correctly do this would be highly appreciated
Thanks in advance
In class A, calling the constructor like this
new A(someClass:mockedSomeClass)
works fine, because in groovy, the default constructor that is generated implicitly, supports setting the value of any field by passing a named parameter which is supported only in a default constructor. You had one field (someClass) which you had passed through the constructor, which was OK.
However, in class B you have an explicit constructor with two arguments. Note that you can call this constructor only with these specified two arguments (i.e. int a, String b) since it's explicitly defined like that. Remember that this is not a default constructor as in class A, so it doesn't automatically support setting a field by passing a named parameter.
Long story short, to make it work, you have to explicitly specify also the third argument:
class B{
@Autowired
private SomeClass someClass;
public B(int a,String b, SomeClass someClass)
{
//method implementation
this.someClass = someClass;
}
And then you can call it like this:
def b=new B(10, "g", mockedSomeClass)
An alternative approach:
The approach from above is the one I would prefer since it is a bit cleaner. The reason is that it is better to have all mandatory dependencies in the constructor to avoid confusion.
However, if for some reason it's not OK for you to change the Java source code, you can also solve it by creating the object like this:
def b=new B(10, "g")
b.someClass = mockedSomeClass
In the above example, we are first creating the object by calling the explicit constructor of class B, which takes 2 parameters. Then we set the someClass field (this looks like assigning the private field manually but in fact we are setting it through the setter which is generated automatically in groovy, you can read about the implicit getter and setters here: http://groovy-lang.org/style-guide.html#_getters_and_setters ).