I am attempting to use Spock to create an integration test around a Spring application. As it is not a Spring Boot application and the @SpringBootTest
annotation interfered significantly with the app's initialization, I am using a minimal configuration.
I specifically need to stub a service in my app that returns objects of type Message
; in the actual app these objects would come from a third-party vendor's library and they cannot be instantiated or subclassed, nor do their members have setters, so my only option is to create Stub
s for them. However, with this current configuration (I've simplified the test significantly just to get the gist across):
@ContextConfiguration([TestSetup]) // supplies actual Spring beans including some JPA repos
class LogicSpec extends Specification {
@SpringBean
RestService restService = Stub()
@Autowired
ServiceUnderTest sut
@Autowired
SomeJPARepo repository;
def 'should do some business logic'() {
given:
Message m = new Stub() {
getStatus() >> "stubbed status"
}
restService.getMessage(_ as String) >> {
m
}
when:
sut.businessMethod()
then:
// just checking for side effects that `businessMethod` causes, no mocks being matched against
assert repository.findAll().every { it.processed == true }
}
}
}
Internally, the ServiceUnderTest.businessMethod()
is using the Message
object like this:
restService.getMessage(sid).getStatus() // should be "stubbed status"; always evaluates to null
however, every method of the Message
stub always returns null regardless of whether I have defined a behavior for it. The Message
objects must return specific values from its getters for the test to work. I would prefer to not have to declare every Message
stub as its own @SpringBean
; I need to eventually expand the test to use several different Message
stub objects. I don't need mocks or spies because the number of invocations of RestService
's methods doesn't matter, I just need it to emit proper stubs for ServiceUnderTest
to chew on. Apologies if this question is unusual or I've missed something obvious; I'm slightly oblivious to Spock's notion of lifecycle, and the waters have been especially muddied with the addition of the Spring extension.
I discovered the answer soon after writing this, but just for posterity; the third-party Message
class is declared as final
and thus can't be subclassed; Spock was creating stubs for them but silently failing to add the overridden mock methods. I ended up using PowerMockito to remove this limitation; however this interfered with collecting test coverage metrics, so I instead used a wrapper class that can be mocked and used it everywhere in my code the original Message class was:
public class MessageWrapper {
public MessageWrapper(Message from) {...}
}
it's an extra bit of headache, but it was necessary because test coverage was required in this case. There also seems to be a promising Spock-specific mocking utility that will mock final classes, but I haven't tested it nor do I know if it will interfere with collecting coverage metrics like PowerMockito does.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.