I just added spock to a Grails 2.2.3 project
I added the following dependency to Buildonfig.groovy:
plugins {
test(":spock:0.7")
}
Then created my Specification class, "test/unit/LocationSpec.groovy:
import grails.test.mixin.*
import org.junit.*
import spock.lang.*
/**
* See the API for {#link grails.test.mixin.support.GrailsUnitTestMixin} for usage instructions
*/
#TestFor(Location)
class LocationSpec extends Specification {
def setup() {
}
def cleanup() {
}
def "compare"() {
when:
def loc1 = new Location(description:descr1)
def loc2 = new Location(description:descr2)
then:
loc1.compareTo(loc2) == descr1.compareTo(descr2)
where:
descr1 | descr2 | pidm1 | pidm2
"foo" | "foo" | 1333868 | 1333868
}
}
However I am getting the following errors with the Specification import line:
Groovy:unable to resolve class spock.lang.Specification
Derp! R.T.F.M.
From http://grails.org/plugin/spock:
Grails 2.2 uses Groovy 2.0, which requires a special Spock
version. So to use the Spock plugin with Grails 2.2, modify you
BuildConfig.groovy file to include the following:
grails.project.dependency.resolution = {
repositories {
grailsCentral()
mavenCentral()
}
dependencies {
test "org.spockframework:spock-grails-support:0.7-groovy-2.0"
}
plugins {
test(":spock:0.7") { exclude "spock-grails-support" }
}
}
Related
I'm running Grails 2.1.1, and i'm looking for a way to get the value of variable set in production while i'm running on test environment.
The config file :
development {
config.url = "http://local"
}
test {
config.url = "http://test.lan"
}
production {
config.url = "http://prod.lan"
}
The only way i know to get config variables is grailsApplication.config.url
The standard config setup only looks at the current environment. Holders has the same current config as grailsApplication. You have to slurp the config again. Try using ConfigurationHelper. A spock test is below. (Note the sometimes doubled config.config is because the first config is the property (or short name for getConfig() method) and your key contains the second config.)
import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import spock.lang.Specification
import org.codehaus.groovy.grails.commons.cfg.ConfigurationHelper
#TestMixin(GrailsUnitTestMixin)
class ConfigSpec extends Specification {
void "test prod config"() {
def configSlurper = ConfigurationHelper.getConfigSlurper('production',null)
def configObject = configSlurper.parse(grailsApplication.classLoader.loadClass(grailsApplication.CONFIG_CLASS))
expect:
configObject.config.url == "http://prod.lan"
}
void "test dev config"() {
def configSlurper = ConfigurationHelper.getConfigSlurper('development',null)
def configObject = configSlurper.parse(grailsApplication.classLoader.loadClass(grailsApplication.CONFIG_CLASS))
expect:
configObject.config.url == "http://local"
}
void "test grailsApplication config"() {
expect:
grailsApplication.config.config.url == "http://test.lan"
}
void "test Holders config"() {
expect:
grails.util.Holders.config.config.url == "http://test.lan"
}
}
Check out Holders: https://gist.github.com/mathifonseca/ab443f1502bfd9461943
import grails.util.Holders
class FooService {
def foo() {
def devUrl = Holders.config.url
assert devUrl == "http://local"
}
}
I've recently upgraded to grails 3.3.1 and realised that grails.test.mixin.Mock has been pulled to separate project which has been build just for backward compatibility according to my understanding org.grails:grails-test-mixins:3.3.0.
I've been using #Mock annotation to mock Grails service injected into groovy/src class under test. What is the tactic to mock collaborating services in this case? Is there anything from Spock what I can use or should I fallback to grails-test-mixins plugin?
Class under test:
import gra
ils.util.Holders
import grails.util.Holders
class SomeUtilClass {
static MyService myService = Holders.grailsApplication.mainContext.getBean("myService")
static String myMethod() {
// here is some code
return myService.myServiceMethod()
}
}
My test spec (Grails 3.2.1):
import grails.test.mixin.Mock
import spock.lang.Specification
#Mock([MyService])
class ValidatorUtilsTest extends Specification {
def 'my test'() {
when:
def result = SomeUtilClass.myMethod()
then:
result == "result"
}
}
Due to you use Holders.grailsApplication in your SomeUtilClass, you can try to add #Integration annotation:
import grails.testing.mixin.integration.Integration
import spock.lang.Specification
#Integration
class ValidatorUtilsTest extends Specification {
def 'my test'() {
when:
def result = SomeUtilClass.myMethod()
then:
result == "result"
}
}
Not sure, but hope it work for you.
Try with this code
#TestMixin(GrailsUnitTestMixin)
#Mock([your domains here])
class ValidatorUtilsTest extends Specification {
static doWithSpring = {
myService(MyService)
}
def 'my test'() {
when:
def result = SomeUtilClass.myMethod()
then:
result == "result"
}
}
Remove the #Mock annotation and implement ServiceUnitTest<MyService> in your test class.
When I run tests with the Build-Test-Data plugin in grails 3 I see the following error.
groovy.lang.MissingMethodException: No signature of method: com...Item.save() is applicable for argument types: () values: [] Possible solutions: last(), wait(), any(), saveAll([Ljava.lang.Object;), saveAll(java.lang.Iterable), last(java.lang.String)
This is typically around a .save() or a .build() I am not a test guru so anyone know what is up?
Update
The example looks like this...
import grails.buildtestdata.mixin.Build
#Build(Author)
class AuthorUnitTests {
void testAuthorStuff() {
def author = Author.build()
...
}
}
My Code looks like...
#TestFor(Item)
#Build([Item])
class ItemSpec extends Specification
{
...
def "Blah Blah"() {
given:
Item i = Item.build(id: 1)
}
}
Below unit test passes in Grails 3.1.1:
package com.example
import grails.test.mixin.TestFor
import spock.lang.Specification
import grails.buildtestdata.mixin.Build
#TestFor(Item)
#Build(Item)
class ItemSpec extends Specification {
void "test something"() {
expect:
Item.build(name: 'Test').name == 'Test'
}
}
build.gradle
compile 'org.grails.plugins:build-test-data:3.0.0'
Make sure to build/compile the app once the plugin GAV added to build.gradle:
gradlew build
should do.
Grails 2.4.x here.
I have a requirement that all the methods of all my Grails services, generated by grails create-service <xyz>, be "wrapped"/intercepted with the following logic:
try {
executeTheMethod()
} catch(MyAppException maExc) {
log.error(ExceptionUtils.getStackTrace(maExc))
myAppExceptionHandler.handleOrRethrow(maExc)
}
Where:
log.error(...) is the SLF4J-provided logger you get when you annotate your class with the #Slf4j annotation; and
ExceptionUtils is the one from org.apache.commons:commons-lang3:3.4; and
myAppExceptionHandler is of type com.example.myapp.MyAppExceptionHandler; and
This behavior exists (or has the option to exist in the event that it needs to be explicitly called somehow) for each method defined in a Grails service
So obviously this wrapper code needs to include import statements for those classes as well.
So for example if I have a WidgetService that looks like this:
class WidgetService {
WidgetDataService widgetDataService = new WidgetDataService()
Widget getWidgetById(Long widgetId) {
List<Widget> widgets = widgetDataService.getAllWidgets()
widgets.each {
if(it.id.equals(widgetId)) {
return it
}
}
return null
}
}
Then after this Groovy/Grails/closure magic occurs I need the code to behave as if I had written it like:
import groovy.util.logging.Slf4j
import org.apache.commons.lang3.exception.ExceptionUtils
import com.example.myapp.MyAppExceptionHandler
#Slf4j
class WidgetService {
WidgetDataService widgetDataService = new WidgetDataService()
MyAppExceptionHandler myAppExceptionHandler = new MyAppExceptionHandler()
Widget getWidgetById(Long widgetId) {
try {
List<Widget> widgets = widgetDataService.getAllWidgets()
widgets.each {
if(it.id.equals(widgetId)) {
return it
}
}
return null
} catch(MyAppException maExc) {
log.error(ExceptionUtils.getStackTrace(maExc))
myAppExceptionHandler.handleOrRethrow(maExc)
}
}
}
Any ideas as to how I might be able to achieve this? I'm worried that a pure Groovy closure might interfere somehow with whatever Grails is doing to its services under the hood at runtime (since they are all classes that don't explicitly extend a parent class).
Here is what I was trying to pin point in my comment:
package com.example
import groovy.util.logging.Log4j
#Log4j
trait SomeTrait {
def withErrorHandler(Closure clos) {
try {
clos()
} catch(Exception e) {
log.error e.message
throw new ApplicationSpecificException(
"Application Specific Message: ${e.message}"
)
}
}
}
Service class:
package com.example
class SampleService implements SomeTrait {
def throwingException() {
withErrorHandler {
throw new Exception("I am an exception")
}
}
def notThrowingException() {
withErrorHandler {
println "foo bar"
}
}
}
Test:
package com.example
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(SampleService)
class SampleServiceSpec extends Specification {
void "test something"() {
when:
service.throwingException()
then:
ApplicationSpecificException e = thrown(ApplicationSpecificException)
e.message == "Application Specific Message: I am an exception"
}
void "test something again"() {
when:
service.notThrowingException()
then:
notThrown(Exception)
}
}
Here is the sample app.
Grails 3.0.9 but it should not matter. this is applicable for Grails 2.4.*
You can intercept the calls to your Service class methods either using MetaInjection or Spring AOP. So you don't have to write closure in each Service class. You can look into this blog that explains both the approaches with examples.
How does one integration-test (Grails) a controller with no inputs and a render view? Here is my controller code and test; the test looks correct but throws a "java.lang.Exception: No tests found matching grails test target pattern filter" error. many thanks for your help. -ryan
Controller code section:
class ReportSiteErrorsController {
static allowedMethods = [reportError: 'GET', saveReportError: 'POST']
def mailService
#Transactional(readOnly = true)
def reportError() {
render(view:'reportError', model:[])
}
}
Integration Test:
#TestFor(ReportSiteErrorsController)
class ReportSiteErrorsControllerTests extends DbunitGroovyTestCase {
#Test
void "test report error"() {
controller.reportError()
assert view == "reportError"
}
}
Leave the extension off in your command line. You are supposed to be specifying the name of the test, not the name of the file in which it is defined.
Use something like...
grails test-app integration: NameOfTest
Not something like...
grails test-app integration: NameOfTest.groovy
I hope that helps.
in Grails 2.4 the default syntax to test render "hello" would be:
import grails.test.mixin.TestFor
import spock.lang.Specification
/**
* See the API for {#link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
#TestFor(SimpleController)
class SimpleControllerSpec extends Specification {
def setup() {
}
def cleanup() {
}
void "test something"() {
controller.index()
expect:
response.text == "hello"
}
}
The assert won't do for me. See also: the Grails Documentation