I'm trying to write a that needs to the request.getHeader('X-File-Size') to return a Long. So I tried to write the test like this:
given:
MockHttpServletRequest request = new MockHttpServletRequest()
request.getHeader('X-File-Size') >> 2L
when:
controller.handle()
then:
1 * serviceMock.upload(_ as Long)
And this is what my controller looks like:
def handle() {
def fileSize = request.getHeader('X-File-Size') as Long
uploadFileService.upload(fileSize)
}
But it says that I am passing a null to the service method instead of a string. I thought the mock would return a long instead of a null.
With this line of code:
MockHttpServletRequest request = new MockHttpServletRequest()
You don't create a mock but a real object. To create a mocked object You need to use Mock or GroovyMock method from test's superclass (should be Specification). So:
MockHttpServletRequest request = Mock()//GroovyMock()
request.getHeader('X-File-Size') >> 2L
Once a mock request is available when testing controllers, have you tried this?
setup:
def key = 'X-File-Size'
def value = 2L
request.addHeader(key, value)
when:
controller.handle()
then:
1 * serviceMock.upload(value)
Related
EDIT 2: Figured out how to pass an integer, however my now my test is failing because the value coming back is empty but the render is the correct value on the web page.
EDIT: I've figured out how to pass values by POST using the request.method, however i now can't figure out how to pass an int into the controller using request, as each addParameter expects a string.
I have a convert application in grails, where both the binary and hex service take a parameter via post before converting it to either binary or hex and returning the result. I'm now writing some Spock tests to test each service however i can't seem to figure out how to test the service if the parameter is required to be sent via POST rather than GET.
Binary Convert Service:
def binary() {
if (request.method == 'POST') {
if (session.user) {
Integer number = params.getInt('number')
String binary = Integer.toBinaryString(number)
def r = new Results()
r.customerID = session["id"]
r.username = session["username"]
r.ConvertService = "binary"
r.number = number
r.result = binary
r.date = new Date()
r.time = new Timestamp(System.currentTimeMillis())
if(r.save()) {
render binary
} else {
render r.getErrors()
}
} else {
redirect(controller: 'main')
}
} else {
response.sendError(405)
}
}
Spock test:
void "Binary Service should return 1100"() {
given:
def convert = new ConvertController()
when:
def result = convert.binary(12)
then:
result == 1100
}
This is what my test returns right now:
groovy.lang.MissingMethodException: No signature of method: eadassignment.ConvertController.binary() is applicable for argument types: (java.lang.Integer) values: [12]
Possible solutions: binary(), any(), <init>(), index(), every(), find()
at org.codehaus.groovy.grails.plugins.web.api.ControllerTagLibraryApi.methodMissing(ControllerTagLibraryApi.java:97)
at eadassignment.ConvertControllerSpec.Binary Service should return 1100(ConvertControllerSpec.groovy:22)
Figured out all my problems. Last one was because the function checked if a valid user existed which the test was failing for obvious reasons.
I know that to access a variable from within the Config.groovy file,
grailsApplication.config.someValue.anotherValue
I want to use a variable within this path because I want to get a URL from the config file. The value foo is passed in as a parameter to the method which will be called a number of times using different variables based on other factors.
def foo = "anothervalue"
grailsApplication.config.someValue.${ foo }.
The actual path to the value I want in the config stays the same as in the first instance.
I have tried:
grailsApplication.config.someValue.${ foo }
grailsApplication.config.someValue${ foo }
grailsApplication.config.someValue + "${ foo }"
grailsApplication.config.someValue + ".${ foo }"
grailsApplication.config.someValue + ${ foo }
grailsApplication.config.someValue."${ foo }" must works.
grailsApplication.config returns a groovy.util.ConfigObject like groovy.util.ConfigSlurper.parse() so you can see how it works in the follow example:
import groovy.util.ConfigSlurper
def configTxt = '''
prop1 {
prop2 {
person.name = 'paco'
}
}
'''
def config = new ConfigSlurper().parse(configTxt)
def foo = "prop2"
println config.prop1."${foo}" // prints [person:[name:paco]]
Hope this helps,
more natural would be grailsApplication.config.someValue[ foo ]
I am new to Spock f/w and trying to learn it. I've written some sample code, where I expect that println(list.size()) statement under when section will print the value 10 (as this call been stubbed under given section). But I am getting 0 (seems like a default value for return type i.e int). Can you please help me understand it?
def "size of list test "() {
given:
ArrayList list = Mock()
list.size() >> 10
when:
list.add(1)
list.add(2)
println(list.size())
then:
1*list.size()
}
When you both mock and verify the interaction the value returned form mock should be configured in then block. The following example works well:
#Grab('org.spockframework:spock-core:0.7-groovy-2.0')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class Test extends Specification {
def 'sample spec'() {
given:
ArrayList list = Mock()
when:
list.add(1)
list.add(2)
println(list.size())
then:
1 * list.size() >> 10
}
}
Really my question is "Can the code sample below be even smaller? Basically the code sample is designed to first look through a list of objects, find the most granular (in this case it is branch) and then query backwards depending on what object it finds.
1 - If it finds a branch, return the findAllBy against the branch
2 - If it finds a department, return the findAllBy against the department
3 - If it finds an organization, return the findAllBy against the organization
The goal is to find the most granular object (which is why order is important), but do I need to have two separate blocks (one to define the objects, the other to check if they exist)? Or can those two executions be made into one command...
def resp
def srt = [sort:"name", order:"asc"]
def branch = listObjects.find{it instanceof Branch}
def department = listObjects.find{it instanceof Department}
def organization = listObjects.find{it instanceof Organization}
resp = !resp && branch ? Employees.findAllByBranch(branch,srt) : resp
resp = !resp && department ? Employees.findAllByDepartment(department,srt) : resp
resp = !resp && organization ? Employees.findAllByOrganization(organization,srt) : resp
return resp
What I'm thinking is something along the lines of this:
def resp
resp = Employees.findAllByBranch(listObjects.find{it instanceof Branch})
resp = !resp ? Employees.findAllByDepartment(listObjects.find{it instanceof Department}) : resp
resp = !resp ? Employees.findAllByOrganization(listObjects.find{it instanceof Organization}) : resp
But I believe that will throw an exception since those objects might be null
You can shorten it up a bit more with findResult instead of a for in loop with a variable you need to def outside:
def listObjects // = some predetermined list that you've apparently created
def srt = [sort:"name", order:"asc"]
def result = [Branch, Department, Organization].findResult { clazz ->
listObjects?.find { it.class.isAssignableFrom(clazz) }?.with { foundObj ->
Employees."findAllBy${clazz.name}"(foundObj, srt)
}
}
findResult is similar to find, but it returns the result from the first non-null item rather than the item itself. It avoids the need for a separate collection variable outside of the loop.
Edit: what I had previously didn't quite match the behavior that I think you were looking for (I don't think the other answers do either, but I could be misunderstanding). You have to ensure that there's something found in the list before doing the findAllBy or else you could pull back null items which is not what you're looking for.
In real, production code, I'd actually do things a bit differently though. I'd leverage the JVM type system to only have to spin through the listObjects once and short circuit when it found the first Branch/Department/Organization like this:
def listObjects
def sort = [sort:"name", order:"asc"]
def result = listObjects?.findResult { findEmployeesFor(it, sort) }
... // then have these methods to actually exercise the type specific findEmployeesFor
def findEmployeesFor(Branch branch, sort) { Employees.findAllByBranch(branch, sort) }
def findEmployeesFor(Department department, sort { Employees.findAllByDepartment(department, sort)}
def findEmployeesFor(Organization organization, sort { Employees.findAllByOrganization(organization, sort)}
def findEmployeesFor(Object obj, sort) { return null } // if listObjects can hold non/branch/department/organization objects
I think that this code is actually clearer and it reduces the number of times we iterate over the list and the number of reflection calls we need to make.
Edit:
A for in loop is more efficient, since you want to break processing on first non-null result (i.e. in Groovy we cannot break out of a closure iteration with "return" or "break").
def resp
for(clazz in [Branch,Department,Organization]) {
resp = Employees."findAllBy${clazz.name}"(listObjects?.find{it instanceof $clazz})
if(resp) return
}
if(resp) // do something...
Original:
List results = [Branch,Department,Organization].collect{clazz->
Employees."findAllBy${clazz.name}"(listObjects?.find{it instanceof $clazz})
}
Enjoy Groovy ;--)
I think #virtualeyes nearly had it, but instead of a collect (which as he says you can't break out of), you want to use a find, as that stops running the first valid result it gets:
List results = [Branch,Department,Organization].find { clazz->
Employees."findAllBy${clazz.name}"(listObjects?.find{it instanceof clazz})
}
I've got a domain class which I want to, at run time, do a database call to populate a list of objects as a property. I have a tree with a 'headMember' property and that property is an object which has the following function:
def marriages = {
def marriages = Marriage.findAll("from Marriage as m where m.mainMember.name=:name", [name:name])
return [marriages:marriages]
}
in my GSP, I use ${tree?.headMember?.marriages} to access the 'headMember' property of the model which is passed to the view 'tree' from the following function in the relevant controller:
def show = {
def tree = Tree.get(params.id)
render(view:'show', model:[tree:tree])
}
when I view this in my browser, i get:
Member$_closure1#3708ab98
where I'd expect a list.
Any ideas what I'm doing wrong?
Cheers.
When you call marriages, you are calling a closure and this closure is returned. I think that you should rework it to be a method, something like that:
static transients = ['marriages'] // tell hibernate that marriages is not a persistent property
List<Marriages> getMarriages(){
return Marriage.findAll("from Marriage as m where m.mainMember.name=:name", [name:name])
}
This way, when you call ${tree?.headMember?.marriages} in your GSP, the getMarriages() method is called and list of marriages should be returned.