How to pass auto wired dependencies as mock while unit testing a class which has constructors with arguments

Krishna :

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

Marko Previsic :

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 ).

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=163084&siteId=1