Can Spock Mock a Java constructor
Solution 1
Since the class under test is written in Groovy, you should be able to mock the constructor call by way of a global Groovy Mock/Stub/Spy (see Mocking Constructors in the Spock Reference Documentation). However, a better solution is to decouple the implementation of the MyConfigurator
class, in order to make it more testable. For example, you could add a second constructor and/or static method that allows to pass an instance of SolrZkClient
(or a base interface, if there is one). Then you can easily pass in a mock.
Solution 2
You can use GroovySpy for mocking constructors in Spock
For example:
def 'my test'() {
given:
def solrZkClient = GroovySpy(SolrZkClient.class,global: true);
when:
MyConfigurator.staticMethodName('hostName:2181')
then:
// assertions
}
Related videos on Youtube
JoeG
Updated on June 11, 2022Comments
-
JoeG almost 2 years
Trying to broaden the appeal of Spock at work and run into this issue. Actually trying to write Unit Tests for a Groovy class, but one that calls out to Java. A static method calls a private constructor. The code looks like:
private MyConfigurator(String zkConnectionString){ solrZkClient = new SolrZkClient(zkConnectionString, 30000, 30000, new OnReconnect() { @Override public void command() { . . . } }); }
"SolrZkClient" is from third party (Apache) Java library. Since it tries to connect to ZooKeeper, I would like to mock that out for this Unit Test (rather than running one internally as part of the unit test).
My test gets to the constructor without difficulty, but I can't get past that ctor:
def 'my test'() { when: MyConfigurator.staticMethodName('hostName:2181') then: // assertions }
Is there anyway to do this?
-
JoeG about 10 yearsThanks Peter, seems like very 'common-sense' advice. Been delaying accepting this answer as putting it into practice has been problematic. Examination of even the small amount of code shows why. The purpose of the class is to be an Abstraction that hides the underlying details of SolrCloud configuration. To 'abstract away' those details, all I need is a connectString. Thus passing in the object the class is trying to hide is not really an option. Will spend more time on this today and I will comment again.
-
Peter Niederwieser about 10 yearsWhy can't you add a second constructor?
-
JoeG about 10 yearsThat would break the encapsulation - one of the purposes of the class is to hide the construction of the SolrZkClient, not to pass that up the calling chain.
-
Peter Niederwieser about 10 yearsYou can make the constructor package-private, and add a comment (or a
@OnlyForTesting
annotation). It's common to slightly open up a class for better testability. -
Beckster about 4 yearsthe question asked for a constructor mocking. This is mocking a static method