What should be outcome of this Mock test? - spock

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
}
}

Related

Groovy - Append values to variables in a string

Lets assume I have a domain class called Template that looks somewhat like this:
class Template{
String subject
...
}
I save an instance of this class:
Template t=new Template(subject:'Hello ${name}').save()
Now, I fetch this instance inside a method as follows:
def render(Long id){
String name='foo'
Template t= Template.get(id)
println t.subject
}
I want the "println t.subject" to be printed as "Hello foo". What I get is "Hello ${name}".
I want t.subject to dynamically replace the value of variable name - "foo" in place of ${name}.
Can this be achieved in groovy?
I cannot find any documentation of how to do this, or why this cannot be done.
Update:
I tried this on my GroovyConsole.
class Entity{
String name
}
class Template{
String name
String subject
}
String renderTemplate(Template template, Entity entity){
return template.subject
}
Entity e = new Entity(name:'product')
Template template=new Template(name:'emailTemplate',subject:'Product ${e.name}')
renderTemplate(template,e)
The Output I got was:
Result: Product product
class Template {
String subject
// ...
}
Template t = new Template(subject: 'Hello, ${name}').save()
Important: Use single quotes in 'Hello, ${name}' or you will get an error.
def render(Long id) {
String name = "world"
Template t = Template.get(id)
​def engine = new groovy.text.GStringTemplateEngine()
def subject = engine
.createTemplate(t.subject)
.make(name: name)​
println subject
}
There are a couple of things wrong with the code shown. You have this:
class Template{
String subject
...
}
Then you have this:
Template t=new Template(subject:"Hello ${name}").save()
The Groovy String assigned to the subject property will be evaluated as soon as you assign it to subject because subject is a String. The actual value will depend on the value of the name property that is in scope when that code executes.
Later you have this:
def render(Long id){
String name="foo"
Template t= Template.get(id)
println t.subject
}
It looks like you are wanting that local name property to be substituted into a Groovy String that has been assigned to t.subject, but that isn't how Groovy works. t.subject is not a Groovy String. It is a String.
Separate from that you comment that when you println t.subject that the output is "Hello ${name}". I don't think that is possible, but if that is what you are seeing, then I guess it is.
You can use a transient property to emulate the required behavior:
class Template{
String subject
String getSubjectPretty(){ "Hello $subject" }
static transients = ['subjectPretty']
}
Then you can use:
println Template.get(1).subjectPretty

Grails - access data within Config.groovy whilst using variable in path

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 ]

Grails: How to fetch a single item via named queries and additional criteria closure

I am using Grails 2.4.3 and having trouble with named queries.
For example I have this
class Product {
Customer customer
...
static namedQueries = {
byCustomer { Customer c ->
eq('customer', c)
}
}
...
}
Now I can do
Product.byCustomer(customer).list()
I event can do
Product.byCustomer(customer).list(pagination + sorting ) {
...
gt('price', 23.5)
}
If I want a single object from gorm with criterias on it, I usually do
Product.createCriteria().get {
....
eq('name', 'foo')
}
This will return the first matching Product with name == 'foo'
Now, what I want to do is this:
Product.byCustomer(customer).get {
...
eq('type', 'bar')
}
This gives me:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server
version for the right syntax to use near 'from product this_)' at line 1. Stacktrace follows:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB server version for the right syntax to use near
'from product this_)' at line 1
I also tried this:
Product.byCustomer(customer) {
...
eq('type', 'bar')
}.get()
which does also not work, since byCustomer(...) returns a collection.
What do I miss here ? I am really wondering cause all other methods seem to work, except .get() :
Product.byCustomer(customer).count {
...
eq('type', 'bar')
}
(this is working)
I really appreciate any help. Thanks!
UPDATE:
As pointed out there are several options are given if you just want to query a fixed set of properties:
With where clause:
Product.byCustomer(customer).findWhere([type: 'bar'])
With another named query for "type"
Product.byCustomer(customer).byType('bar').get()
Problem: I have a dynamic set of criterias I want to add - and cannot create a named queries for all properties in my domain class.
UPDATE 2:
Example how I want to dynamically build by criteria, based on conditions:
Product p = Product.byCustomer(customer).get() {
if (condition) {
eq('a', params.int('bar'))
gt('b', params.int('foo'))
items {
eq('c', 'baz')
}
} else {
...
}
}
ANSWER
I think I found the way this will work for me. As I use Grails > 2.0 I can use
where-queries which will return DetachedCriteria
DetachedCriteria has the missing get() method and I even can mix findWhere - like syntax with builder syntax - check this out:
Product.where { foo == '5' && bar > 8 }.get()
Or
Product.where { foo == '5' && bar > 8 }.build {
items {
eq('baz', 5)
}
}.get()
In both closures (where + build) I can dynamically add conditions.
Now the final part - reuse the namedQueries which already exists in the above Query
Product.where { foo == '5' && bar > 8 }.build {
items {
eq('baz', 5)
}
Product.byCustomer(customer)
}.get()
Sweet! Unfortunately I cannot answer my own question yet :)
UPDATE
The last part is NOT working. How can I mix DetachedCriteria and named queries ?
Since the result of a named query with a closure argument is a java.util.ArrayList you should be able to do
Product.byCustomer(customer){
...
eq('type', 'bar')
}.getAt(0)
If the result is an empty list it will return null, otherwise it will return the first entry (in your case the only one). Tried with Grails 2.4.3.

mockhttpservletrequest spock returning null

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)

How to remove object from database in test in Grails

I have got a domain:
MyClass
with fields
String a
String b
I got a test:
void testRemoveMyClass() {
MyClass x = new MyClass()
x.setId(3)
x.setA("AAA")
x.setB("BBB")
x.save()
if (!MyClass.exists(3)) {
fail "Object does not exist"
}
x.delete()
if (MyClass.exists(3)) {
fail "Object exists"
}
}
And the second 'fail' fails. How can I delete this object by Id?
First of all: do NOT use typed references, use:
def x = new MyClass()
Very good reading about his topic: http://blog.springsource.org/2010/07/28/gorm-gotchas-part-3/
Your object still exists, but it should not be persisted anymore. Try by the end of the test, instead of the second exists():
def y = MyClass.findById(3)
assert y == null
BTW, you can create your domain objects eaisier via map in constructor:
def x = new MyClass(id: 3, a: 'AAA', b: 'BBB')

Resources