I am using Spock to create integration tests for my Spring Boot Application, but I'm having trouble figuring out how to mock part of a Service for all my test cases.
My app writes to an Azure Cosmos database running in Gremlin Graph mode, and since I don't know of any in-memory databases to adequately simulate it, I would like to make sure any service that writes to my development database only interacts with entities labeled with the current test's random UUID. So any service that reads/writes to the database needs to make sure to include the current test ID in any query.
What's the best way to mock a couple reused methods in an abstract base class via Spock?
GraphService.groovy <== The abstract class with some methods I wish to mock.
abstract class GraphService {
@Autowired
protected GraphTraversalSource g
protected GraphTraversal buildBaseQuery() {
return g.V()
}
protected GraphTraversal buildBaseCreationQuery(String label) {
return g.addV(label)
}
}
Several database searching/modifying services inherit the above class. For all of my tests, instead of g.V()
I want g.V().has("testID", testId)
and instead of g.addV(label)
I want g.addV(label).property("testID", testId)
. How can I accomplish this across all my integration tests? I tried creating a base-specification class that specified this behavior, but it didn't work.
TestConfig.groovy
@Configuration
class TestConfig {
@Bean
@Primary
GraphPersistenceService persistenceService(
GraphTraversalSource g) {
DetachedMockFactory mockFactory = new DetachedMockFactory()
GraphPersistenceService persistenceService = mockFactory.Stub( //Mock doesn't work either
[constructorArgs: [g]], GraphPersistenceService)
return graphPersistenceService
}
}
BaseIntegrationTest.groovy
class BaseIntegrationTest extends Specification {
@Autowired
TestUtil testUtil
@Autowired
GraphTraversalSource g
@Autowired
GraphPersistenceService persistenceService
def setup() {
persistenceService.buildBaseQuery >> g.V().has("testID", testUtil.id)
persistenceService.buildBaseCreationQuery(_ as String) >> { label ->
g.addV(label).property("testID", testUtil.id)
}
}
def cleanup() {
testUtil.removeAllEntitiesWithCurrentTestId()
}
}
And then in an actual test:
@SpringBootTest(classes = MyGraphApplication.class)
@ContextConfiguration(classes = [GraphDbConfig.class, TestConfig.class])
@ActiveProfiles("test")
@TestPropertySource(locations = 'classpath:application-local.properties')
class UserOfPersistenceServiceSpec extends BaseIntegrationTest {
@Autowired
UserOfGraphPersistenceService userOfPersistenceService
def "Can create a bunch of vertices"() {
expect:
userOfPersistenceService.createABunchOfVertices() == 5
}
}
PS. I'm using Spring 1.5.10.RELEASE and groovy 2.4.15...
If upgrading to Spock 1.2 is an option for you, I suggest ditching the TestConfig class and using the @SpringBean
annotation.
This is an example of how I have it set up in my tests:
@ActiveProfiles(["integrationtest"])
@DirtiesContext
abstract class IntegrationTest extends Specification {
@SpringBean
EurekaClient eurekaClient = Mock() {
getNextServerFromEureka(*_) >> Mock(InstanceInfo) {
getHomePageUrl() >> "test.test"
}
}
// ... other stuff
}