What is the correct Spock syntax for Grails? - unit-testing

I have a Grails 2.5.0 app running and this test:
package moduleextractor
import grails.test.mixin.TestFor
import spock.lang.Specification
/**
* See the API for {#link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
#TestFor(ExtractorController)
class ExtractorControllerSpec extends Specification {
def moduleDataService
def mockFile
def setup() {
moduleDataService = Mock(ModuleDataService)
mockFile = Mock(File)
}
def cleanup() {
}
void "calls the moduleDataService"() {
given: 'a term is passed'
params.termCode = termCode
when: 'the getModuleData action is called'
controller.getModuleData()
then: 'the service is called 1 time'
1 * moduleDataService.getDataFile(termCode, 'json') >> mockFile
where:
termCode = "201415"
}
}
If I run grails test-app unit:spock I get this:
| Tests PASSED - view reports in /home/foo/Projects/moduleExtractor/target/test-reports
I don't understand why it sees 2 tests. I have not included spock in my BuildConfig file as it is already included in Grails 2.5.0. Also the test is not supposed to pass, as I do not have a service yet. Why does it pass?
Also when I run this grails test-app ExtractorController I get another result:
| Running 2 unit tests...
| Running 2 unit tests... 1 of 2
| Failure: calls the moduleDataService(moduleextractor.ExtractorControllerSpec)
| Too few invocations for:
1 * moduleDataService.getDataFile(termCode, 'json') >> mockFile (0 invocations)
Unmatched invocations (ordered by similarity):
None
at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:78)
at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:76)
at moduleextractor.ExtractorControllerSpec.calls the moduleDataService(ExtractorControllerSpec.groovy:27)
| Completed 1 unit test, 1 failed in 0m 3s
| Tests FAILED - view reports in /home/foo/Projects/moduleExtractor/target/test-reports
| Error Forked Grails VM exited with error
If I run grails test-app unit: I get:
| Running 4 unit tests...
| Running 4 unit tests... 1 of 4
| Failure: calls the moduleDataService(moduleextractor.ExtractorControllerSpec)
| Too few invocations for:
1 * moduleDataService.getDataFile(termCode, 'json') >> mockFile (0 invocations)
Unmatched invocations (ordered by similarity):
None
at org.spockframework.mock.runtime.InteractionScope.verifyInteractions(InteractionScope.java:78)
at org.spockframework.mock.runtime.MockController.leaveScope(MockController.java:76)
at moduleextractor.ExtractorControllerSpec.calls the moduleDataService(ExtractorControllerSpec.groovy:27)
| Completed 1 unit test, 1 failed in 0m 3s
| Tests FAILED - view reports in /home/foo/Projects/moduleExtractor/target/test-reports
| Error Forked Grails VM exited with error
First of all could somebody tell me what is the correct syntax to run spock tests?
Also what is the difference between having unit and unit: and unit:spock in the command?
(Since Spock comes with Grails 2.5.0, it will run spocks tests anyway.)
What is the correct syntax and why does it sees 2 tests instead of 1 ?

Don't be concerned with the number of tests. It's never been a problem for me. You can always check the report HTML file to see exactly what ran.
I always run my tests with either
grails test-app
or
grails test-app ExtractorController
The error you're getting means you coded the test to expect moduleDataService.getDataFile() to get called with parameters null and 'json' when controller.getModuleData() is called. However, moduleDataService.getDataFile() never got called, so the test failed.
Spock takes some getting used to. I recommend looking at examples in the Grails documentation and reading the Spock Framework Reference.

First question: for the 'grails test-app unit:spock', have you looked at the results to see the tests it says passed? The test count at the CLI can be wrong, check your results to see what actually ran (if no tests actually ran, then there were no failures).
Your test method doesn't start with 'test', nor does it have a #Test annotation, so the 'void "calls the moduleDataService"' isn't being seen as a spock test case (I believe that is the reason).
When you run 'grails test-app ExtractorController', you aren't specifying that it has to be a spock test, so grails testing finds and executes the 'calls the moduleDataService' test method.
Since spock is the de facto testing framework, you can just use:
grails test-app -unit
Second question:
#TestFor creates your controller, but if you're running a unit test, then the usual grails magic isn't happening. Your controller code is executing in isolation. If your ExtractorController usually has the moduleDataService injected, you'll have to take care of that.
I work in grails 2.4.3, and here would be my interpretation of your test (assuredly in need of tweaking since I'm inferring a lot in this example):
import grails.test.mixin.TestFor
import grails.test.mixin.Mock
import spock.lang.specification
import some.pkg.ModuleDataService // if necessary
import some.pkg.File // if necessary
#TestFor(ExtractorController)
#Mock([ModuleDataService, File])
class ExtractorControllerSpec extends Specification
def "test callsModuleDataService once for a termCode"() {
setup:
def mockFile = mockFor(File)
def mockService = mockFor(ModuleDataService, true) // loose mock
// in this mockService, we expect getDataFile to be called
// just once, with two parameters, and it'll return a mocked
// file
mockService.demand.getDataFile(1) { String termCode, String fmt ->
return mockFile.createMock()
}
controller.moduleDataService = mockService.createMock()
when:
controller.params.termCode = "201415"
controller.getModuleData()
then:
response.status == 200 // all good?
}
}
Last question: is that a Banner term code? (just curious)

Related

How do I make the `groovy` command exit non-zero for failing JUnit4 tests?

When running JUnit tests with the groovy command using the built-in automatic test runner, it exits 0 even when tests fail. I'd like the command to exit non-zero if there are test failures. Is there a way I can do this?
#!/usr/bin/env groovy
import org.junit.*
class BasicTest {
#Test
void test_failure() {
assert false
}
}
$ groovy --version
Groovy Version: 3.0.2 JVM: 13.0.2 Vendor: Oracle Corporation OS: Mac OS X
$ groovy basic_test.groovy
JUnit 4 Runner, Tests: 1, Failures: 1, Time: 8
Test Failure: test_failure(BasicTest)
Assertion failed:
assert false
at org.codehaus.groovy.runtime.InvokerHelper.assertFailed(InvokerHelper.java:434)
...
$ echo $?
0
Thanks folks!
Not seen people running tests like that before... (writing them as a *nix script)
You can do this though, to catch a failure, and exiting with 1
#!/usr/bin/env groovy
import org.junit.*
import org.junit.rules.*
class BasicTest {
#Rule
public TestRule watchman = [
failed: {e, d ->
println d
e.printStackTrace()
System.exit(1)
}
] as TestWatcher
#Test
void test_failure() {
assert false
}
}

Grails - Apache Tika plugin test-app failure

I'm learning how to use the Apache Tika plugin. I've just copied the code from github and I get failure error when unit testing.
This is the unit test
import grails.test.mixin.TestFor
import spock.lang.Specification
/**
* Test for tikaService: try to parse test data.
*/
#TestFor(TikaService)
class TikaServiceSpec extends Specification {
def 'Parse a word file to XML'() {
given:
def file = new File('parserTest.doc')
when:
def xml = service.parseFile(file)
then:
def doc = new XmlSlurper().parseText(xml)
doc.body.p.find{
it.text() == 'This is a simple test document'
}
}
}
This is the error I get.
Running 5 unit tests... 8 of 8
| Failure: Parse a word file to XML(com.myApp.TikaServiceSpec)
| Condition not satisfied:
doc.body.p.find{ it.text() == 'This is a simple test document' }
| | | |
| | | groovy.util.slurpersupport.NoChildren#4c2a4e84
| | Tika Parser Test
| | This is a simple test document
| Tika Parser Test
| This is a simple test document
Tika Parser Test
This is a simple test document
at com.myApp.TikaServiceSpec.Parse a word file to XML(TikaServiceSpec.groovy:21)
What am I doing wrong?
dependencies {
compile('org.apache.tika:tika-core:0.7')
compile('org.apache.tika:tika-parsers:0.7') { excludes "xercesImpl", "xmlParserAPIs", "xml-apis", "log4j" }
}
Thanks to #Gagravarr, the problem has been solved. I used the version 1.12 and it worked.
The repo is https://repo1.maven.org/maven2/org/apache/tika/

Grails Unit Test Exception java.lang.Exception: No tests found matching grails test target pattern filter

I am just starting to learn Grails testing and I tried to write my first grails test.For this, I created a fresh grails project and created a controller named com.rahulserver.SomeController:
package com.rahulserver
class SomeController {
def index() { }
def someAction(){
}
}
When I created this controller, grails automatically created a com.rahulserver.SomeControllerSpec under test/unit folder.
Here is my SomeControllerSpec.groovy:
package com.rahulserver
import grails.test.mixin.TestFor
import spock.lang.Specification
/**
* See the API for {#link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
#TestFor(SomeController)
class SomeControllerSpec extends Specification {
def setup() {
}
def cleanup() {
}
void testSomeAction() {
assert 1==1
}
}
When I right click this class, and run this test, I get following:
Testing started at 5:21 PM ...
|Loading Grails 2.4.3
|Configuring classpath
.
|Environment set to test
....................................
|Running without daemon...
..........................................
|Compiling 1 source files
.
|Running 1 unit test...|Running 1 unit test... 1 of 1
--Output from initializationError--
Failure: |
initializationError(org.junit.runner.manipulation.Filter)
|
java.lang.Exception: No tests found matching grails test target pattern filter from org.junit.runner.Request$1#1f0f9da5
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:35)
at org.junit.runner.JUnitCore.run(JUnitCore.java:138)
No tests found matching grails test target pattern filter from org.junit.runner.Request$1#1f0f9da5
java.lang.Exception: No tests found matching grails test target pattern filter from org.junit.runner.Request$1#1f0f9da5
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:35)
at org.junit.runner.JUnitCore.run(JUnitCore.java:138)
|Completed 1 unit test, 1 failed in 0m 0s
.Tests FAILED
|
- view reports in D:\115Labs\grailsunittestdemo\target\test-reports
Error |
Forked Grails VM exited with error
Process finished with exit code 1
So why is it failing?
EDIT
I am using grails 2.4.3
The unit tests are defined with Spock by default:
void testSomeAction() {
assert 1==1
}
Should be written as:
void "Test some action"() {
expect:
1==1
}
See http://spockframework.github.io/spock/docs/1.0/index.html

Grails unit test case showing Completed 0 spock test, 0 failed

I am new to Grails. I am using version 2.2.2
My test cases are not running even it says test cases passed.
I get the following message after running the test case.
Resolving [test] dependencies...
Resolving [runtime] dependencies...
| Compiling 1 source files.
| Error log4j:ERROR Property missing when configuring log4j: grails
| Error log4j:ERROR Property missing when configuring log4j: grails
| Error log4j:ERROR WARNING: Exception occured configuring log4j logging: null
| Completed 0 spock test, 0 failed in 1409ms
| Tests PASSED - view reports in D:\workspace_idea\optapp\target\test-reports
#TestFor(KpiLog)
#TestMixin(DomainClassUnitTestMixin)
#Mock(KpiLog)
class KpiLogSpec extends Specification {
void "savelog"() {
prinln "*********"
when:
def kpiLog = new KpiLog(scenarioId: 1, kpiId: 2, deltaKpi: 5)
kpiLog.save(flush: true)
then:
KpiLog.list()!= null
}
void testSaveFacebookUser(){
//given
def kpiLog = new KpiLog(scenarioId: 1, kpiId: 2, deltaKpi: 5)
//adminRole.addToPermissions("*:*")
kpiLog.save()
}
}
Can some one please tell me what is it that I am doing wrong?
I am running the test case as grails test-app -unit KpiLogSpec
Here is the log4j section from the Config.groovy file
log4j = {
// Example of changing the log pattern for the default console
// appender:
//
//appenders {
// console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n')
//}
debug 'grails.app'
error 'org.codehaus.groovy.grails.web.servlet', // controllers
'org.codehaus.groovy.grails.web.pages', // GSP
'org.codehaus.groovy.grails.web.sitemesh', // layouts
'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
'org.codehaus.groovy.grails.web.mapping', // URL mapping
'org.codehaus.groovy.grails.commons', // core / classloading
'org.codehaus.groovy.grails.plugins', // plugins
'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
'org.springframework',
'org.hibernate',
'net.sf.ehcache.hibernate'
appenders {
console name:'S', layout:pattern(conversionPattern: '%d %-5p %c - %m%n')
//rollingFile name: 'R', file:'/usr/local/jd/logs/optimizer.log',maxFileSize: '5000000KB'
rollingFile name: 'R', file:grails.config.logPath, maxFileSize: '5000000KB'
environments {
production {
appender new AWSSNSAppender(
name:'SNS' ,
topicName:config.optimizer.snsAppender.topicName,
topicSubject:config.optimizer.snsAppender.topicSubject,
awsAccessKey:config.optimizer.aws.accessKey,
awsSecretKey:config.optimizer.aws.secretKey,
threshold:Level.toLevel(optimizer.snsAppender.threshold, Level.ERROR)
)
}
}
}
info R: ['NotifierService', 'aggDataStackLog','constraintGroupLog','pageFilterLog','alertDebugLog','dacCacLog','tpFlagExportImportLog','timelog','calculationProgress','dictionaryLog','loginServiceLog', 'calculateScenarioLog','connectionLog','dataLabelServiceLog','cross-section-service','qe-basic-executor-service','qe-plan-enumerator-impl-service','qe-basic-planenum-ssservice','ct-dimension-hierarchy-service','cbRuleLog'],additivity:true
error SNS: ['aggDataStackLog','constraintGroupLog','pageFilterLog','alertDebugLog','dacCacLog','tpFlagExportImportLog','timelog','calculationProgress','dictionaryLog','loginServiceLog', 'calculateScenarioLog','connectionLog','dataLabelServiceLog','cross-section-service','qe-basic-executor-service','qe-plan-enumerator-impl-service','qe-basic-planenum-ssservice','ct-dimension-hierarchy-service','cbRuleLog'],additivity:true
//info SNS: ['aggDataStackLog','calculateScenarioLog']
/*root {
error 'R'
additivity = true
} */
}
Here is the test code which I ran.
#TestMixin(GrailsUnitTestMixin)
class FooSpec extends Specification {
def setup() {
}
def cleanup() {
}
void "test something"() {
println "****************testing in real "
assertTrue(1==1)
}
}
Run the test case like this
grails test-app unit: KpiLog
The important thing is that you use unit: instead of -unit and KpiLog instead of KpiLogSpec
Then do not define the variable log.
def log = new KpiLog(scenarioId: 1, kpiId: 2, deltaKpi: 5)
It is reserved for logging in Grails classes (controllers, services, ...). Rename the variable from log to kpiLog
def kpiLog = new KpiLog(scenarioId: 1, kpiId: 2, deltaKpi: 5)
A simple log configuration can be
log4j = {
appenders {
console name: 'stdout', layout: pattern(conversionPattern: '%d [%t] %-5p %c - %m%n')
}
error 'org.codehaus.groovy.grails.web.servlet', // controllers
'org.codehaus.groovy.grails.web.pages', // GSP
'org.codehaus.groovy.grails.web.sitemesh', // layouts
'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
'org.codehaus.groovy.grails.web.mapping', // URL mapping
'org.codehaus.groovy.grails.commons', // core / classloading
'org.codehaus.groovy.grails.plugins', // plugins
'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
'org.springframework',
'org.hibernate',
'net.sf.ehcache.hibernate'
}
Finally, it is working. It was because of the jar msutil in the lib folder. I got this information from one of my friends that it has some incompatibility. I changed the jar which he sent and things started working.
Thanks a lot saw303 for keeping patience with my questions.

Grails possible race condition in database session?

I'm learning grails and read Grails In Action book. Try perform some tests from it, but got strange behaviour for me. I have next simple integration test:
#Test
public void testProjections() throws Exception {
User user1 = new User(mail: 'test1#test.tld', password: 'password1').save(flush: true)
User user2 = new User(mail: 'test2#test.tld', password: 'password2').save(flush: true)
assertNotNull(user1)
assertNotNull(user2)
// Chain add Tag to Post
user1.addToPosts(new Post(content: 'First').addToTags(new Tag(name: 'tag-0')))
// Separate add tag to post
Post post = user1.posts.iterator().next()
Tag tag1 = new Tag(name: 'tag-1')
post.addToTags(tag1)
// http://stackoverflow.com/questions/6288991/do-i-ever-need-to-explicitly-flush-gorm-save-calls-in-grails
// Have tried with and without next line without success:
//sessionFactory.getCurrentSession().flush()
assertEquals(['tag-0', 'tag-1'], user1.posts.iterator().next().tags*.name.sort()) // line 154
…
}
Then I run it twice subsequently:
grails>
grails> test-app -rerun -integration
| Running 5 integration tests... 2 of 5
| Failure: testProjections(com.tariffus.QueryIntegrationTests)
| java.lang.AssertionError: expected:<[tag-0, tag-1]> but was:<[tag-1]>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:743)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at com.tariffus.QueryIntegrationTests.testProjections(QueryIntegrationTests.groovy:154)
| Completed 5 integration tests, 1 failed in 0m 0s
| Tests FAILED - view reports in /home/pasha/Projects/grails/com.tariffus/target/test-reports
grails>
grails> test-app -rerun -integration
| Running 5 integration tests... 2 of 5
| Failure: testProjections(com.tariffus.QueryIntegrationTests)
| java.lang.AssertionError: expected:<[3, 1, 2]> but was:<[[tag-1, tag-2, tag-0, tag-5, tag-3, tag-4], [tag-6]]>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:743)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at com.tariffus.QueryIntegrationTests.testProjections(QueryIntegrationTests.groovy:164)
| Completed 5 integration tests, 1 failed in 0m 0s
| Tests FAILED - view reports in /home/pasha/Projects/grails/com.tariffus/target/test-reports
grails>
As you can see first fails on line 157 and second, runned just after that in second without any modification goes further.
I use Postgres database and environment test configured dataSource in mode dbCreate = 'update'.
What I do incorrect and why it works sometimes?
I would say that a source of problem is this line:
user1.addToPosts(new Post(content: 'First').addToTags(new Tag(name: 'tag-0')))
These dynamic addTo* methods does not propagate save to the associated instances until save() is called on the parent instance. So calling save() on user1 after should fix it:
user1.addToPosts(new Post(content: 'First').addToTags(new Tag(name: 'tag-0')))
user1.save()
This should propagate save() to Post instance at first and then to Tag instance transitively.