Mocking Spring beans with Spock
I love Spock testing framework, it has much more elegant syntax that JUnit. Also, I think it has a gentle learning curve compared to JUnit. Not so long ago to Mock or Stub Spring context beans was a pain in the butt. But Spock 1.2 version introduced an easier way to Mock and Stub spring beans.
In my examples I’ll be using Spring Boot 2.1.
Old way
In the old days to Mock or Stub Spring bean, we had to create separate Spring configuration which
created our beans using DetachedMockFactory
.
Example of old way:
@SpringBootTest
@Import(TestConfig)
class AccountServiceIntegrationSpec extends Specification {
@Autowired
AccountRepository accountRepository
@Autowired
AccountService accountService
def 'should save new account'() {
given:
AccountDTO account = new AccountDTO(name: "Income", type: INCOME)
Account accountWithId = new Account(id: 5, name: "Income", type: INCOME)
accountRepository.save(_ as Account) >> accountWithId
when:
AccountDTO result = accountService.createAccount(account)
then:
with(result) {
id == 5
name == 'Income'
type == INCOME
}
}
static class TestConfig {
DetachedMockFactory mockFactory = new DetachedMockFactory()
@Bean
@Primary
AccountRepository accountRepositoryStub() {
return mockFactory.Stub(AccountRepository)
}
}
}
As you can see it contains quite a lot boilerplate code to Stub single bean. And it was error prone, you had to remember to @Import
your TestConfig
class.
Post Spock 1.2 way
Thankfully Spock 1.2 improved bean Mocking and Stubbing quite a lot and it became a trivial operation.
Example:
@SpringBootTest
class AccountServiceIntegrationSpec extends Specification {
@SpringBean
AccountRepository accountRepository = Stub()
@Autowired
AccountService accountService
def 'should save new account'() {
given:
AccountDTO account = new AccountDTO(name: "Income", type: INCOME)
Account accountWithId = new Account(id: 5, name: "Income", type: INCOME)
accountRepository.save(_ as Account) >> accountWithId
when:
AccountDTO result = accountService.createAccount(account)
then:
with(result) {
id == 5
name == 'Income'
type == INCOME
}
}
}
Everything is done with only two lines. It differs from regular Stubbing only by single @SpringBean
annotation.
@SpringBean
AccountRepository accountRepository = Stub()
To use this @SpringBean
annotation you must include org.spockframework:spock-spring
dependency in your classpath
.
Also, there is @SpringSpy
annotation for creating spies, but generally I’m against spying, because usage of Spies, in my opinion, is bad code smell.
Summary
Spock 1.2 version solved an old issue with Mocking and Stubbing Spring beans. You can read more about the latest Spock releases on their GitHub page.
If you have any questions feel free to leave a comment below.
Happy testing :)