I am trying to mock the groovy.sql.Sql call(query, params[], closure) class.
Below is method, within a DatabaseService class file, that I am attempting this on.
public void getUsers(List<User> developerList, Sql sql) {
sql.call("{? = call GETUSERS()}", [Sql.resultSet(OracleTypes.CURSOR)]) { result ->
while (result.next()) {
User user = new User()
user .email = result.EMAIL
user .lastName = result.LASTNAME
}
}
}
My mock does achieve the task, however, I do not want the mocked closure to execute. I want to mock the .call(,,_) method to only skip the database logic, and return back a list to the closure in the getUsers() method. I want the closure to execute in getUsers() method, not the mocked up method.
Below is the mockup I have written in SPOCK.
void "test getUsers(list,sql) some results"() {
DataSource mockedSource = Mock(DataSource)
Sql mockedSql = Mock(Sql)
DatabaseService databaseService = new DatabaseService()
databaseService.dataSource = mockedSource
List<User> userList= new ArrayList<>();
when:
databaseService.getUsers(userList, mockedSql)
then:
1 * mockedSql.call(_, _, _) >> { return [[EMAIL: "A", LASTNAME: "B"]] }
userList.size() == 1
}
As imagined, this mockup overwrites the original method closure, and my list is never populated.. I certainly do not want to rewrite my class to use Java, nor can I change the stored procedure that is executed.
try :
int resultSetIdx = 0
def resutSet = Mock(ResultSet)
...
then:
1 * mockedSql.call(_, _, _) >> { args -> args[2].call(resultSet) }
2 * mockedResultset.next() >> { ++resultSetIdx > 1 ? false: true}
1 * mockedResultset.getString("EMAIL") >> "A"
In the getUsers method() change
user.lastName = result.LASTNAME
user.email = result.EMAIL
To
user.lastName = result.getString("LASTNAME")
user.email = result.getString("EMAIL")
However, you shouldn't mock Sql, but rewrite your service/dao layer to be more testable. test the dao with an inmemory db, and the service layer with a mocked dao.
Related
I wrote service for manual requeuing events from one queue to another.
public class ReQueueService {
private final RabbitTemplate rabbitTemplate;
public void retry() {
InfoLog infoLog;
while (rabbitTemplate != null &&
(infoLog = (InfoLog) rabbitTemplate.receiveAndConvert(EVENT_WAITING_FOR_REQUEUE)) != null
) {
rabbitTemplate.convertAndSend(SOME_QUEUE, infoLog.getSomeEvent());
}
}
}
The problem I am facing is getting:
Too many invocations for:
1 * rabbitTemplate.convertAndSend(SOME_QUEUE, _ as SomeEvent) >> {
arguments ->
assert infoLog.getSomeEvent() == arguments[1]
} (2 invocations)
Matching invocations (ordered by last occurrence):
2 * rabbitTemplate.convertAndSend(SOME_QUEUE, ...
while my code in test looks like this:
class ReQueueServiceTest extends Specification {
def "should resend single event to some queue" () {
given:
InfoLog infoLog = Fixtures.createInfoLog()
def rabbitTemplate = Mock(RabbitTemplate){
receiveAndConvert(EVENT_WAITING_FOR_REQUEUE) >> { infoLog }
}
ReQueueService reSyncService = new ReQueueService(rabbitTemplate)
when:
reSyncService.retry()
then:
1 * rabbitTemplate.convertAndSend(SOME_QUEUE, _ as SomeEvent) >> {
arguments ->
assert infoLog.getSomeEvent() == arguments[1]
}
}
}
The question is why I have 2 invocations, if I stubb only one event?
EDIT:
link to repo with example: https://gitlab.com/bartekwichowski/spock-too-many
Thanks for the repo link. As soon as I could run the test and inspect the behaviour live, it was pretty easy to find out what was wrong. First I will make an educated guess about what you actually want to test:
The mock's receiveAndConvert method should return str when it is called first and then null when called again.
Subsequently you want to verify that the while loop runs exactly 1 iteration, i.e. that convertAndSend is called with exactly the parameters you expect.
This can be achieved by
receiveAndConvert("FOO") >>> [str, null]
1 * rabbitTemplate.convertAndSend("BAR", str) (no need for ugly assertions inside a stubbed method, the parameters are verified against your parameter constraints already)
If I refactor your specification a little bit for prettier variable names and less verbosity, it looks like this:
class ReSyncServiceTest extends Specification {
def "should resend single event to resource sync queue"() {
given:
def message = "someValue"
def rabbitTemplate = Mock(RabbitTemplate) {
receiveAndConvert("FOO") >>> [message, null]
}
when:
new ReSyncService(rabbitTemplate).retry()
then:
1 * rabbitTemplate.convertAndSend("BAR", message)
}
}
P.S.: Your version with the assertion inside does not return anything explicitly, but implicitly the result of the last assertion. Be careful with that. With >> { ... } you are stubbing the method result! It would always return true in the version you have in Git and the test only terminates because you added the 1 * limit. If it was not there, you would have an endless loop. Your code did not do what you thought it did. Maybe the Spock manual can help you there. :-)
P.P.S.: Maybe you want to refactor your application code to be a bit easier to understand and maintain and to be a little less "smart". Also there is no need to check that rabbitTemplate != null in every iteration, once should be enough. How about this?
#Slf4j
#Service
#AllArgsConstructor
public class ReSyncService {
private final RabbitTemplate rabbitTemplate;
public void retry() {
if (rabbitTemplate == null)
return;
String event;
while (null != (event = getEventFromQueue()))
rabbitTemplate.convertAndSend("BAR", event);
}
protected String getEventFromQueue() {
return (String) rabbitTemplate.receiveAndConvert("FOO");
}
}
I have a service that I'm trying to test. Inside this service is another UserAPIService that I want to mock. To mock it I'm doing the following:
given:
def userAPIServiceMock = mockFor(UserAPIService)
userAPIServiceMock.demand.createUser { def apiToken, firstname, lastname, email -> return true
}
service.userAPIService = userAPIServiceMock.createMock()
In the demand closure, I don't really care what arguments are passed to the createUser method. Is there a way I can say "regardless of the arguments passed to the createUser method, return true."
In other words, how can I change
userAPIServiceMock.demand.createUser { def apiToken, firstname, lastname, email -> return true
to
userAPIServiceMock.demand.createUser { [any arguments] -> return true
This is possible with Spock.
The syntax is as follows:
mock.method(*_) >> { args -> true }
Not sure how your Grails service needs to be mocked, but here's a full, general example in Spock:
interface Service {
boolean hej( String s, boolean b, char c )
}
class ExampleSpec extends Specification {
def "mock method with any number of args"() {
when:
def mock = Mock( Service )
mock.hej(*_) >> { args -> true }
then:
mock.hej( 'hi', true, 'a' as char ) == true
}
}
args is a List containing the actual arguments, which you can inspect in the closure and return the appropriate value.
I want to use EHCache in my grails application. I want to cache a method with #Cacheable.
I am testing this scenario:
Simple test class:
class MyTestClassB {
def a
def b
#Override
boolean equals(Object obj) {
println ("New A" + this.a)
println ("Olda A" + obj.a)
if (this.a != obj.a) {
return false
}
return super.equals(obj)
}
}
Method to be cached in a service class:
#Transactional
class HelpService {
#Cacheable('newcache')
def inlineCacheService(def param) {
println ("I am in the function")
MyTestClass a = new MyTestClass()
a.paramA = new Date()
a.paramB = [
id: "1",
data: "f"
]
return a
}
}
So I call the method in the controller:
MyTestClassB c1 = new MyTestClassB()
c1.a = "paramc1"
render "1: " + helpService.inlineCacheService(c1).paramA
c1.a = "paramc1neu"
render "<br/>1: " + helpService.inlineCacheService(c1).paramA
The problem in this scenario is: I changed the value of parameter object, so I expect that I don't get the cached value. But the second call of inlineCacheService reads the value from the cache. What is the problem here? Do I missunderstand something?
The hashCode was missing. After implementation the cache works now as excpected. Thanks to #rcgeorge23
I have a mapper that uses a \Zend\Db\TableGateway\TableGateway via DI. I have mocked it for the unit test.Here is the test:
class EMSMapperTest extends PHPUnit_Framework_TestCase
{
public function testFetchAllReturnsAllScheduledBlocks()
{
$resultSet = new ResultSet();
$mockTableGateway = $this->getMock(
'Zend\Db\TableGateway\TableGateway',
array('select','getTable'),
array(),
'',
false
);
$mockTableGateway->expects($this->once())
->method('selectWith')
->with()
->will($this->returnValue($resultSet));
$mockTableGateway->expects($this->once())
->method('getTable')
->with()
->will($this->returnValue('table'));
$emsMapper = new EMSMapper($mockTableGateway);
$this->assertSame($resultSet, $emsMapper->fetchAll());
}
}
and the mapper being tested:
class EMSMapper extends BaseMapper
{
public function fetchAll( $building = null,
$room = null, DateRange $range = null )
{
$select = new Select;
$table = $this->tableGateway->getTable();
$select->from($table);
if(!empty($building))
{
$select->where(array('buildingCode'=>$building));
}
if(!empty($room))
{
$select->where(array("room"=>$room));
}
if(is_array($range))
{
if(!empty($range['start']))
{
$select->where("start >= '{$range['start']}'");
}
if(!empty($range['stop']))
{
$select->where("stop <= '{$range['stop']}'");
}
}
$resultSet = $this->tableGateway->selectWith($select);
$results = array();
foreach($resultSet as $r)
{
$results[] = $r;
}
return $results;
}
}
After returning a string from the TableGateway's getTable() method the unit test says:
There was 1 error:
1) EMSTest\Model\EMSMapperTest::testFetchAllReturnsAllScheduledBlocks
Zend\Db\TableGateway\Exception\RuntimeException:
This table does not have an Adapter setup
If would seem that the Select requires the table string supplied to the from() method have an adapter associated with it. How do I supply a mock of the required adapter?
Thanks for the help!
Your code is using the actual code for selectWith. This calls an initialize method that throws your error.
Change you mock code to:
$mockTableGateway = $this->getMock(
'Zend\Db\TableGateway\TableGateway',
array('selectWith','getTable'),
array(),
'',
false
);
This should properly configure your mock.
http://phpunit.de/manual/current/en/test-doubles.html
From the manual:
When the second (optional) parameter is provided, only the methods whose names are in the array are replaced with a configurable test double. The behavior of the other methods is not changed. Providing NULL as the parameter means that no methods will be replaced.
So you were setting the expects on the correct method, but were replacing the wrong one with your mock and so the real code was being executed.
Does anyone know of a way to avoid repeating a closure when emitting the same object more than once using the latest version of the Grails JSONBuilder?
I have a Group domain object that contains sets of Members and Leaders. I would like to find a way to emit a person without having to cut and paste the closure.
def builder = new JSONBuilder()
def result = builder.build {
array {
Group.list().each { Group group ->
g = {
id = group.id
name = group.name
members = array {
group.members?.person?.sort().each { Person person ->
m = { // Person closure copy #1
id = person.id
firstName = person.firstName
lastName = person.lastName
}
}
}
leaders = array {
group.leaders?.person?.sort().each { Person person ->
l = { // Person closure copy #2
id = person.id
firstName = person.firstName
lastName = person.lastName
}
}
}
}
}
}
}
I have tried defining the closure separately but that leads to errors such as: exception: No such property: id for class:.
Some notes:
1) The domain objects in the example are greatly simplified. I'm using JSONBuilder instead of render Group.list() as JSON or render Group.list().encodeAsJSON because I need to control what parts of my objects are encoded.
2) I'll accept authoritative answers that explain why this can't be done.
After repeated failures using closures, I have a solution. It doesn't use a closure directly but instead uses a closure that returns a map.
class Person {
...
def toMap = {
def map = [:]
map["id"] = this.id
map["firstName"] = this.firstName
map["lastName"] = this.lastName
return map
}
}
def builder = new JSONBuilder()
def result = builder.build {
array {
Group.list().each { Group group ->
g = {
id = group.id
name = group.name
members = array {
group.members?.person?.sort().each { Person person ->
m(person.toMap())
}
}
leaders = array {
group.leaders?.person?.sort().each { Person person ->
l(person.toMap())
}
}
}
}
}
}
The m(person.toMap()) syntax isn't intuitive but it works and allows me to avoid repeating myself. This blog entry provides the details and explains the origin of the current Grails JSONBuilder.
You can execute another closure in the same "context" by setting the "delegate" for the closure.
Closures aren't multi-thread safe (only one delegate at a time) so you will have to clone the closure each time if the closures are shared in a singleton class or static variable.
This is just an idea of refactoring the code, it might not work (I didn't test it).
You can replace assignment (=) with "setProperty" and DSL method calls with "invokeMethod" if you have to dynamicly decide the property name or method name in the DSL.
(reference http://groovy.codehaus.org/api/groovy/lang/Closure.html)
def personClosure = { Person person, varname ->
setProperty(varname, {
id = person.id
firstName = person.firstName
lastName = person.lastName
})
}
def groupMembersClosure = { memberList, memberListVarName, memberVarName ->
personClosure.delegate = delegate
setProperty(memberListVarName, array {
memberList?.person?.sort().each personClosure, memberVarName
})
}
def builder = new JSONBuilder()
def result = builder.build {
array {
Group.list().each { Group group ->
g = {
id = group.id
name = group.name
groupMembersClosure.delegate = delegate
groupMembersClosure(group.members, 'members', 'm')
groupMembersClosure(group.leaders, 'leaders', 'l')
}
}
}
}