Grails- spock : turn setup method as normal method - grails

I am trying to write unit for one of my grails service method, the unit test is like
#Shared instance1, instance2, instance3
class testClass extends Specification {
def setup() {
// initaiting some value here
instance1 = new Initate(one:"one")
instance2 = new Initate(one:"one")
instance3 = new Initate(one:"one")
}
def "testmethodcall"() {
//testsetup()
when:
def result = someMethod(value1) // Here is the error
then:
result==value2
where:
value | value1 | value2
instance1 | instance2 | instance3
}
}
for some reason we planned to move the codes inside this setup method to another method and plan to call where it is required, like this
#Shared instance1, instance2, instance3
class testClass {
def testsetup() {
// initialize the code what we initialize in setup
// initaiting some value here
instance1 = new Initate(one:"one")
instance2 = new Initate(one:"one")
instance3 = new Initate(one:"one")
}
def "testmethodcall"() {
testsetup()
when:
def result = someMethod(value1) // Here is the error
then:
result==value2
where:
value | value1 | value2
instance1 | instance2 | instance3
}
}
As of now it is fine, the method call is working fine, even variable were been initialized, but when I trying to use the data column values it is returning null values, but when I change to setup() method I getting the real values. Can someone explain me and How can I able to change the setUp method as normal method

There are few things to note down:-
setup() - is used to run with every test case
setupSpec() - is used to run once for a test class / unit
shared - is visible throughout.And hence must be initialized once, Hence must be within worked upon in setupSpec and not within setup.
cleanup() - is run with every test case
cleanupSpec - is run in last, after all the test cases has run.
Only #Shared and static variables can be accessed from within a where: block.
Seperate inputs and outputs expected with double pipes ||
Apart from these point, in your code testmethodcall method is having syntax errors.
no comparison is done
expect: is missing
why def value is there ,whereas we use data tables variables are declared automatically
Also, value2 is used no where
Also, you stated that you are able to run test cases successfully with above code when setup() method is there, it's just passing silently without failing as both the value and value1 are null.
Below is a modified version of your code
def "test methodcall"(){
setup()
expect:
value == someMethod(value1) // Here is the error
println '----instance1----'+value
println '----instance2----'+value1
println '----instance1----'+instance1
println '----instance2----'+instance2
// instance1 == instance2
where:
value | value1
instance1 | instance2
}
Now see the println output and you will understand the issue.Hope this would get you answer.

Related

What kind of Groovy object is Jenkins "env"?

In Jenkins pipelines, if I assign any key-value to env, I can access it like normal variables in string interpolation and environment variables in shell script. How does this work?
I see the probable implementation here but can't figure out how it works.
[Update]
In below code snippet, I can access the env properties without accessor -->
node {
stage('Preparation') {
env.foo = "bar"
echo "foo is $foo"
}
}
I haven't delved into the Jenkins code, but you could implement something like this by implementing the propertyMissing() method in a class, which would write to the script binding. The propertyMissing method gets called when the code is trying to access a property that is not declared in the class.
class MyEnv {
groovy.lang.Script script
MyEnv( groovy.lang.Script script ) {
this.script = script
}
def propertyMissing( String name ) {
script.getProperty( name )
}
def propertyMissing( String name, value ) {
script.setProperty( name, value )
}
}
def env = new MyEnv( this ) // pass the script context to the class
env.foo = 42 // actually assigns to the script binding
println "env.foo: $env.foo" // prints 42
println "foo: $foo" // prints 42
// It also works the other way around...
foo = 21 // assign to the script binding (Note: "def foo" would not work!)
println "env.foo: $env.foo" // prints 21

Mocking methods in grails integration test carries over to other tests

I have an integration test where I sometimes want to mock the return of a service method. However, I have seen that once I mock that method, the subsequent tests that call it will also use the mocked function.
Is this normal? If so, how can I have test which sometimes use mocked functions and sometimes use the real implementation?
Here is my code:
MyController {
def someService
def save(){
...
def val = someService.methodToMock()//sometimes want to mock other times, not
...
}
}
MyTest {
def "test 1"(){
...
//I want to mock here
myController.someService.metaClass.methodToMock = { [] }
...
myController.save()
}
def "test 2"(){
...
//I don't want to mock here, however
// it is returning the mocked results
myController.save()
}
}
In general you don't want to change anything to do with metaclasses in integration or functional tests, only in unit tests. It's expected that you'll be doing this in unit tests and there's automatic support for restoring the original metaclass after each test or after each test class runs depending on the version of Grails and how things are configured. But this isn't the case in integration tests.
There are several different approaches you can use. If you use untyped dependency injection, e.g. def someService, then you can overwrite the real service instance with anything you want, and as long as it has the method(s) that you'll be invoking during the test method the controller won't know or care that it's not the real service.
I like to use a map of closures in this case, since Groovy will invoke a closure as if it were a method. So for 'test 1' you could do this:
def "test 1"() {
...
def mockedService = [methodToMock: { args -> return ... }]
myController.someService = mockedService
...
myController.save()
}
This works because you get a new instance of the controller for each test, and you change the service just for that instance, but the real service isn't affected at all.
Your controller invokes someService.methodToMock(), which is actually someService.get('methodToMock').call(), but the map access and closure invocation syntax can take advantage of Groovy's syntactic sugar to look like a regular method call.
Another option is to subclass the service and override the method(s) that you want, and replace the injected instance with that. This or something like it would be necessary if you type the dependency injection (e.g. SomeService someService). Either create a named subclass (class TestSomeService extends SomeService { ... }) or create an anonymous inner class:
def "test 1"() {
...
def mockedService = new SomeService() {
def methodToMock(args) {
return ...
}
}
myController.someService = mockedService
...
myController.save()
}
Altering the metaClass in one test will absolutely affect other tests. You're altering the groovy system, and need to perform some special cleanup if you're metaClassing. At the end my methods where I metaClass, I call a function to revoke the metaClass changes, passing in the name of the class that was metaClassed, and the instance metaClassed if there was one.
def "some authenticated method test"() {
given:
def user = new UserDomain(blah blah blah)
controller.metaClass.getAuthenticatedUser = { return user }
when:
controller.authenticatedMethod() // which references the authenticated user
then:
// validate the results
cleanup:
revokeMetaClassChanges(theControllerClass, controller)
}
private def revokeMetaClassChanges(def type, def instance = null) {
GroovySystem.metaClassRegistry.removeMetaClass(type)
if (instance != null) {
instance.metaClass = null
}
}
Alternatively, you can just mock the service in the test. A method similar to that mentioned by Burt could be:
def "some test"() {
given:
def mockSomeService = mockFor(SomeService)
mockSomeService.demand.methodToMock(1) { def args ->
return []
}
controller.someService = mockSomeService.createMock()
when:
controller.save()
then:
// implement your validations/assertions
}

Spock - test fails after interaction testing

This test works only when condition is tested. When mixed with interaction testing, it fails.
class Test extends Specification {
class Inner {
public String greet() {
return "hello"
}
}
def "simple test"() {
given:
def inner = Mock(Inner)
inner.greet() >> { "hi" }
when:
def msg = inner.greet()
then:
1 * inner.greet() // Below will pass when this line commented out.
msg == "hi"
}
}
The test will pass when interaction testing is removed.
Condition not satisfied:
msg == "hi"
| |
| false
null
It should be:
#Grab('org.spockframework:spock-core:0.7-groovy-2.0')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class Test extends Specification {
class Inner {
public String greet() {
return "hello"
}
}
def "simple test"() {
given:
def inner = Mock(Inner)
when:
def msg = inner.greet()
then:
1 * inner.greet() >> "hi"
msg == "hi"
}
}
Let's talk a bit about what's going on. (Or if you don't want to, read the "Scope of Interactions" section.)
What's happening is an issue of scoping. As you may know, you can have multiple sequential when/then pairs; any Mocking done in a then block is actually scoped to only its when block. What happens if the Mocked method was already defined outside the when/then scoping? The Mock defined in the then block takes precedence.
Congratulations! You've stumbled across the only way to overwrite established Mocked values/methods. I spent a long time figuring out how this worked before the new documentation was released.
So we know you're overwriting your mock that defines a value to return. How do we proceed from here?
given:
def inner = Mock(Inner)
1 * inner.greet() >> message
expect:
"hi" = inner.greet()
where:
message = "hi"
Parting thought... I hope you're not testing a value that you set within your test. That's effectively asserting 1 == 1. If you want to test your actual code while testing behavior I'd suggest using a Spy
given:
def inner = Spy(Inner)
1 * inner.greet() >> {
callRealMethod() // Actual method, read the documentation I linked
}
expect:
"hi" = inner.greet()

How to verify argument of method of spying object

I have a class with method save():
public class FilesystemImagePersistenceStrategy implements ImagePersistenceStrategy {
public void save(MultipartFile file, Image image) {
File dest = createFile(image);
writeToFile(file, dest);
}
// protected to allow spying
protected void writeToFile(MultipartFile file, File dest) throws IOException {
IOUtils.copy(file.getInputStream(), new FileOutputStream(dest));
}
}
And now I want to check name of the file before it will be saved:
class FilesystemImagePersistenceStrategyTest extends Specification {
private ImagePersistenceStrategy strategy = Spy(FilesystemImagePersistenceStrategy)
private MultipartFile multipartFile = Mock()
private Image image = TestObjects.createImage()
def "save() should gives proper name to the file"() {
given:
String expectedFileName = ...
when:
strategy.save(multipartFile, image)
then:
1 * strategy.writeToFile({ MultipartFile file, File dest ->
assert dest.name == expectedFileName
return true
})
}
}
But unfortunately it doesn't work, real method invoked instead...
Why it so? And how to check method's argument?
P.S. I also provided an example at http://meetspock.appspot.com/script/5741031244955648
I ended up with the following:
1 * strategy.writeToFile(
multipartFile,
{ assert it.name == expectedFileName; return true }
) >> {}
There assert call needs to show me nice error message, like this:
it.name != expectedFileName
| | | |
| 1.png| 2.png
| false
/tmp/1.png
Also return true is required for case when test fails. Without this statement closure will return false and this method will not be accounted as candidate (and real method will be executed).
The argument constraint specified for 1 * strategy.writeToFile is wrong. There needs to be one constraint per argument, and constraints must not contain assert statements. Additionally, if a spy is to be used as a partial mock, the default response (which calls through to the real method) needs to be suppressed by supplying a stubbed response ("do nothing" in this case). This leads to:
...
then:
1 * strategy.writeToFile(multipartFile, { it.name == expectedFileName }) >> {}
Which can be simplified to:
...
then:
1 * strategy.writeToFile(multipartFile, expectedFileName) >> {}
for multiplicity and assertions on mock, I used the following:
then:
numberOfCalls * mock.accept(_) >> {ArgType arg ->
assert arg.id == my.id
assert arg.minSerial == my.min()
assert arg.maxSerial == my.max()
}

Problems with one-to-many association data binding in an integration test in Grails

I am trying to create an integration test and I am running in a problem in the binding of an association.
I am trying to test a save method in a controller.
I have the domain class Event
class Event {
...
..
.
Organizer organizer
}
In the controller save method I have
def save() {
...
..
.
def passedOrganizerId = params.organizer.id // (1)
//Some comprobations
// if comprobations pass
def event = new Event(params) // (2)
.
}
The method seems to work fine but I want to create an integration test.
class EventControllerTests extends GroovyTestCase {
void testSave() {
def params = [:]
// Params setup (3)
controller.params.putAll(params)
controller.save()
...
..
.
}
}
I have tried several ways to do the params setup but all fail.
If in the test method line (3) I enter: params.organizer.id = 3 it fails because organizer is null
If I enter params['organizer.id'] = 3 then it fails in line (1)
If I enter
params.organizer = [:]
params.organizer.id = 3
It does not fail but the databinding is not working. That it is to say event.organizer is null after line (2)
How to make the data binding work in the test method?
You can set up params in test as follow:
...
controller.params.organizer = Organizer.get(3)
controller.save()
...
i.e. use domain objects as controller parameters directly

Resources