I am attempting to write some basic controller tests and am following the documentation https://docs.grails.org/latest/guide/testing.html. My test currently is unable to find ControllerUnitTest. Is there a dependency that I am missing?
Here is my import
grails.testing.web.controllers.ControllerUnitTest
See the project at https://github.com/jeffbrown/mcroteaucontrollertest.
https://github.com/jeffbrown/mcroteaucontrollertest/blob/master/src/test/groovy/mcroteaucontrollertest/DemoControllerSpec.groovy
package mcroteaucontrollertest
import grails.testing.web.controllers.ControllerUnitTest
import spock.lang.Specification
import static org.springframework.http.HttpStatus.METHOD_NOT_ALLOWED
class DemoControllerSpec extends Specification implements ControllerUnitTest<DemoController> {
void "test GET request"() {
when:
controller.index()
then:
response.text == 'Success'
}
void "test POST request"() {
when:
request.method = 'POST'
controller.index()
then:
response.status == METHOD_NOT_ALLOWED.value()
}
}
The ControllerUnitTest trait is provided by grails-web-testing-support. Make sure you have something like testCompile "org.grails:grails-web-testing-support" as shown at https://github.com/jeffbrown/mcroteaucontrollertest/blob/cf5f09b1c2efaba759f6513301d7b55fcb29979b/build.gradle#L56.
Related
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
I have some code that I am trying to port from Grails 1.3.7 to Grails 2.2.
The current problem is that I have an BaseController class that defines some convenience methods, and specific controllers (ones actually instantiated by Grails) that inherit from it.
package com.fxpal.querium
import grails.converters.JSON
import groovy.lang.Closure;
abstract class BaseController {
protected def executeSafely(Closure c) {
def resp = null
try {
populateContext();
resp = c()
}
catch(Exception ex) {
resp = [error: ex.message]
ex.printStackTrace()
}
def json = resp as JSON
return json
}
protected void populateContext() {
}
}
An example of a derived class is
package com.fxpal.querium
import grails.converters.JSON
import grails.plugins.springsecurity.Secured
import javax.servlet.http.HttpServletResponse
#Secured(['IS_AUTHENTICATED_REMEMBERED'])
class DocumentController extends BaseController {
def grailsApplication
#Secured(['IS_AUTHENTICATED_ANONYMOUSLY'])
def getText = {
try {
String text = new URL(grailsApplication.config.querium.docurl + params.paperId).text
render contentType: 'text/plain', text: text
}
catch(Exception ex) {
render contentType: 'text/plain', text: "Error loading document: ${ex.getMessage()}; please retry"
}
}
...
}
This worked in Grails 1.3.7. When I try to compile my app with Grails 2.2, I get the following error:
C:\code\querium\AppServer-grails-2\grails-app\controllers\com\fxpal\querium\DocumentController.groovy: -1: The return ty
pe of java.lang.Object getGrailsApplication() in com.fxpal.querium.DocumentController is incompatible with org.codehaus.
groovy.grails.commons.GrailsApplication getGrailsApplication() in com.fxpal.querium.BaseController
. At [-1:-1] # line -1, column -1.
Is this pattern no longer supported? I tried adding abstract to be BaseController declaration (it wasn't necessary in Grails 1.3.7), but that didn't seem to make any difference. I compiled my code after a clean, if that matters.
PS: To those who can: please create a grails-2.2 tag
Remove def grailsApplication - the field is already added to the class bytecode via an AST transformation as a typed field (GrailsApplication) so your def field creates a second get/set pair with a weaker type (Object).