Unit testing a GORM call with a closure - unit-testing

I have a Grails service that does a where query like this:
List<Car> search(Long makeId = null) {
Car.where {
join("make")
if(makeId) {
make.id == makeId
}
}.findAll()
}
I'm trying to unit test it with Spock like this:
def setup() {
GroovyMock(Car, global: true)
}
void "test search"() {
when:
service.search()
then:
1 * Car.where {}
}
However, I can't seem to find a way to test the content of the closure.
I can get the test to pass by verifying 1 * Car.where(_), but how can I make assertions on the content of the closure, i.e. that join was called and that the make.id constraint is specified only when needed?

You could set the closure's delegate to be an Mock of DetachedCriteria to make assertions on it. DetachedCriteria is the main class used in gorm to build the query.
Example:
given: 'Mocking DetachedCriteria'
DetachedCriteria detachedCriteriaMock = Mock(DetachedCriteria)
and: 'Just to avoid nullPointerException when findAll() call happens on service'
1 * detachedCriteriaMock.iterator() >> [].listIterator()
when:
service.search(1L)
then:
// Capture the argument
1 * Car.where(_) >> { args ->
args[0].delegate = detachedCriteriaMock
args[0].call()
return detachedCriteriaMock
}
// Join is a method on detached criteria
1 * detachedCriteriaMock.join('make')
// Make is an association, so detachedCriteria uses the methodMissing to find the property.
// In this case, we call the closure setting the delegate to the mock
1 * detachedCriteriaMock.methodMissing('make', _) >> { args ->
// args[1] is the list of arguments.
// args[1][0] is the closure itself passed to detachedCriteria
args[1][0].delegate = detachedCriteriaMock
args[1][0].call()
}
// If id is passed, it must compare (eq method) with value 1
1 * detachedCriteriaMock.eq('id', 1L)

Related

how to mock/match lambda in kotlin method signature

I have some code on the follwing form:
#Language("SQL")
val someSql = """
SELECT foo
FROM bar
WHERE foo = :foo
"""
return session.select(some, mapOf("foo" to foo)) {
MyObject(
foo = it.string("foo"),
)
}.firstOrNull()
which use the below from com.github.andrewoma.kwery.core. Note the lambda in the method signature:
fun <R> select(#Language("SQL") sql: String,
parameters: Map<String, Any?> = mapOf(),
options: StatementOptions = defaultOptions,
mapper: (Row) -> R): List<R>
I use mockitokotlin2.
I need to return an instance of MyObject when the session select method is called with a select query (containing "SELECT foo").
I was thinking I could pass a mock into the lambda as below (but then it wont match the method call I am trying to mock). The below code is an attempt. But it never matches in eq(function2):
val function2: (Row) -> Int = mock {
onGeneric { invoke(any()) }.thenReturn(MyObject(foo="test-foo"))
}
val session = mock<Session> {
on { select(sql = any(), parameters = any(), options = any(), mapper = eq(function2))}.thenReturn(listOf(MyObject(foo="test-foo")))
}
function2 in my case is not really a mapper, it is not eq to what I am trying to mock, it never matches and the mock is never called.
So what do I put in the mock of session, select instead of eq(function2) in the code above to get MyObject object returned?
I think you just need to specify they type that your mapper is expected to return when setting up the session mock - in your case looks to be Function1<Row, MyObject>
val session = mock<Session> {
on { select(sql = anyString(), parameters = anyMap(), options = any(), mapper = any<Function1<Row, MyObject>>())}.thenReturn(listOf(MyObject(foo="test-foo")))
}

Mocking object on a Filter in a unit test (Grails)

Given the following setup:
class MockingFilters {
def filters = {
all(controller:"simple", action:"list") {
before = {
log.info "This needs asserting"
return false
}
}
}
}
Is there a way to assert that the log.info has fired? I am unsure how to get a handle on the Filter, and thus be able to interaction test the log object.
void "test list action is filtered"() {
when:
withFilters(action:"list") {
// Important bit
// Not sure how to get a handle to the filter
1 * log.info("This needs asserting")
controller.list()
}
then:
// Whatever here
}
There are also other objects on the Filter that I would like to test, but this example should be reflective of those too.

Using Spock to test Spring JdbcTemplate

I have the following Java 8 DAO method that uses Spring JdbcTemplate to hit a database:
class MyAppDao {
#Inject
DataSource dataSource
public List<String> getFizzByBuzzIds(List<Integer> buzzIds) {
String sql = "SELECT * from buzzes WHERE buzz_id IN ( :buzzIds )";
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
Map<String, Object> paramValues = new HashMap<>(1);
paramValues.put("buzzIds", buzzIds);
List<Buzz> buzzes = jdbcTemplate.query(sql,
paramValues, (rs, rowNum) -> {
return new Buzz(rs.getString("buzz_id"), rs.getString("buzz_key"),
rs.getString("buzz_external_id"));
}
);
List<String> fizzes = figureOutSomehow();
return fizzes;
}
}
I cannot change the dependencies injected into this method. The NamedParameterJdbcTemplate instance must be defined inside this method. The only thing I can mock (easily) is the dataSource.
I am trying (and I know, the method isn't written to be conducive to unit tests at all!) to write a Spock unit test for this, and just want to verify that when getFizzByBuzzIds is called, that jdbcTemplate.query is called (with any arguments).
My best attempt:
def 'getFizzByBuzzIds attempts to get case info from the DB'() {
given:
MyAppDao dao = Spy(MyAppDao, constructorArgs: [ dataSource ]) {
getJdbcTemplate() >> Mock(JdbcTemplate) {
1 * query('', null) // ???
}
}
when:
List<Integer> buzzIds = [1, 2, 3, 4]
dao.getFizzByBuzzIds(buzzIds)
then:
1 * dao.jdbcTemplate.query('', null) // ???
}
How can I configure the Spy and the then block label so that executing getFizzByBuzzIds verifies whether the underlying JdbcTemplate.query(...) method is called?

How do I test that a method was called within a grails asynchronous promise?

I'm trying the verify that a method is called within a promise, using a unit test.
I have a CallerService, that will call classA.methodA() within a task,
class CallerService {
def classA
def callA() {
Promise p = task {
classA.methodA()
}
p.onComplete {
println "complete"
}
p.onError { Throwable err ->
println "there was an error"
}
}
}
and a unit test that mocks ClassA and tries the verify that methodA was called once.
def "calling A"() {
given:"a mock classA"
def mockClassA = Mock(ClassA)
service.classA = mockClassA
when:"callA is called"
service.callA()
then:"methodA should be called once"
1* mockClassA.methodA()
}
The tests fails because the mock was called twice.
| Failure: calling A(promisespike.CallerServiceSpec)
| Too many invocations for:
1* mockClassA.methodA() (2 invocations)
Matching invocations (ordered by last occurrence):
2 * mockClassA.methodA() <-- this triggered the error
Is this the result I should be expecting or have I setup my test incorrectly?

Verify Spock mock with specified timeout

In Mockito there is option to verify if mock method has been called, and specify timeout for this verification (VerificationWithTimeout), for example:
verify(mock, timeout(200).atLeastOnce()).baz();
It there any equivalent to such functionality in Spock?
I was trying to use PollingConditions to satisfy a similar scenario (which wasn't helpful), but instead found satisfaction in Spock's BlockingVariables. To verify that SomeService.method() is invoked at least once in function ClassBeingTested.method() within a given timeout period:
def "verify an interaction happened at least once within 200ms"(){
given:
def result = new BlockingVariable<Boolean>(0.2) // 200ms
SomeService someServiceMock = Mock()
someServiceMock.method() >> {
result.set(true)
}
ClassBeingTested clazz = new ClassBeingTested(someService: someServiceMock)
when:
clazz.someMethod()
then:
result.get()
}
When the result is set, the blocking condition will be satisfied and result.get() would have to return true for the condition to pass. If it fails to be set within 200ms, the test will fail with a timeout exception.
There is no equivalent in Spock. (PollingConditions can only be used for conditions, not for interactions.) The closest you can get is to add a sleep() statement in the then block:
when:
...
then:
sleep(200)
(1.._) * mock.baz()
Using PollingConditions and a boolean variable, the following example evaluates a function until it satisfies an interaction.
def "test the config watcher to reload games if a new customer directory is added"() {
given:
def conditions = new PollingConditions(initialDelay: 1, timeout: 60, factor: 1.25)
def mockGameConfigLoader = Mock(GameConfigLoader)
def gameConfigWatcher= new GameConfigWatcher(mockGameConfigLoader)
boolean gamesReloaded = false
when:
conditions.eventually {
gameConfigWatcher.listenEvents()
assert gamesReloaded
}
then:
1 * mockGameConfigLoader.loadAllGameConfigs() >> {
gamesReloaded = true
}
0 * _
}
This doesn't do exactly what the question asked, but I found it a bit cleaner that using a variable. If you have other conditions to asynchronously test in addition to the interaction, then you can declare the interactions at mock creation time and then use PollingConditions to test the other conditions. PollingConditions will either fail the test or block until the conditions pass, so that by the time the interaction is tested, the method should have been called:
#MicronautTest
class KernelManagerTest extends Specification {
#Inject
KernelManager kernelManager
//create conditions
PollingConditions conditions = new PollingConditions(timeout: 10, initialDelay: 1)
class Exits {
static createKernel (String[] args) {
System.exit(args[0].toInteger())
}
}
def "handles a system exit from within kernel"() {
given:
// set custom kernel
kernelManager.kernelClass = Exits
// create custom logger
kernelManager.log = Mock(Logger) {
1 * warn("Kernel exited unexpectedly.", _ as UnexpectedExitException)
}
when:
// create new kernel (exit 1)
kernelManager.startNewKernel("1")
then:
conditions.eventually {
kernelManager.kernelInstances.size() == 0
kernelManager.kernelThreads.size() == 0
}
}
}