I've created a BaseController that I mixinto other Controllers.
Example:
class BaseController () {
def somemethod () {
return "some method"
}
}
#Mixin(BaseController)
class MyController {
def getsomething() {
def test = somemethod()
return test
}
}
I'm trying to write a test case for MyController however, it fails because it can't find somemethod.
My test currently looks like this
#TestFor(MyController)
class MyControllerSpec extends Specification {
def "test getsomething" () {
when:
def m = controller.getsomething()
then:
response.contentAsString == "some method"
}
}
But I keep getting errors like these:
No signature of method: somemethod() is applicable for argument types: () values: []
Question
How can I write spock test for MyController so that it finds somemethod as well
Does using #TestMixin(BaseController) in the Spock test for MyController work?
Ans:- No, it is not required.
UPDATE
There is a small modification required in MyController. Use render instead of return. Here is the detail:
class BaseController {
def someMethod() {
"Some Method"
}
}
import grails.util.Mixin
//Remember to use Grails #Mixin instead of Groovy #Mixin
#Mixin(BaseController)
class MyController {
def getSomething() {
def test = someMethod()
render test
}
}
//Unit Test
#TestFor(MyController)
class MyControllerUnitSpec extends Specification {
void "test get something"() {
when:
controller.getSomething()
then:
response.contentAsString == "Some Method"
}
}
//Controller Integration Test
import grails.plugin.spock.ControllerSpec
class MyControllerIntSpec extends ControllerSpec {
void "test get something integration"() {
when:
controller.getSomething()
then:
controller.response.contentAsString == "Some Method"
}
}
Notes:-
I found some difficulties while testing which are listed below:-
The above tests passed with an initial run. But, when I changed render to return just to see my tests failing, I got compilation errors because of the Grails #Mixin I used in MyController (two version of withFormat). Sometimes I think it does not play well. Changing the mixin to Groovy #Mixin everything went good. I did not like that. I had to stick to Grails #Mixin. Apparently and surprisingly, doing a grails clean && grails compile eradicated the issue. I was able to use Grails #Mixin properly. I am still looking at this discrepancy.
If the above problem were persistent, I would have thought of adding runtime mixin in the setup() method in unit test.
Like
def setup(){
//I would not like to do the same in Integration test
//Integration test should do it for me atleast.
MyController.mixin BaseController
}
I used ControllerSpec instead of IntegrationSpec in integration test. Seems like injection and convention is maintained better in ControllerSpec for controllers. If you see, nowhere am I instantiating MyContoller in the int test.
I have not tested it in normal Junit's Unit and Integration tests, they should be good as well.
My strong advice is to not use mixins in Grails at all. It generates faulty bahvior in tests. Also you need an extra code to apply these mixins for tests, which is bad.
For further information read this replay: http://grails.1312388.n4.nabble.com/grails-2-2-2-upgrade-from-2-2-0-breaks-mixin-on-controller-tp4645461p4645466.html, which applies to mixins in Grails in general, or take look of many issues reported in comments of this issue: http://jira.grails.org/browse/GRAILS-8652 (classes lose their mixins during unit tests).
Based on the answers in this thread, http://grails.1312388.n4.nabble.com/Testing-a-controller-that-has-a-Mixin-td4645595.html
I ended up using,
void setup() {
MyController.mixin(BaseController)
}
Related
we are preparing for Grails 2.4 upgrade. One of the issues we face is that
most of the command object unit tests fails because of injected properties, like
services, are required to be not null during validation.
Is there any suggested way how to test this? Should we mock all properties although some are not needed for test? or is there a way to do this differently?
After my question is answered by Jeff, I share links with more information about new functionalities:
doWithSpring and doWithConfig are shortly described in What's new in 2.4: http://grails.org/doc/latest/guide/introduction.html#whatsNew24 in Unit Testing improvements section
There is also a JIRA issue with example: https://jira.grails.org/browse/GRAILS-11003
Most unit tests don't want or need the application context all spun up and populated. Unit tests can add whatever they want (or nothing) to the application context. In recent versions of Grails you can do something like this...
A controller and command object:
// grails-app/controllers/demo/DemoController.groovy
package demo
class DemoController {
def processName(SomeCommand co) {
render co.someValue
}
}
class SomeCommand {
String name
def helperService
def getSomeValue() {
helperService.processValue(name)
}
}
A service:
// grails-app/services/demo/HelperService
package demo
class HelperService {
def processValue(String originalValue) {
"__${originalValue}__"
}
}
A unit test:
// grails-app/test/unit/demo/DemoControllerSpec.groovy
package demo
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(DemoController)
class DemoControllerSpec extends Specification {
def doWithSpring = {
helperService HelperService
}
void 'process name'() {
when:
params.name = 'Jeff'
controller.processName()
then:
response.contentAsString == '__Jeff__'
}
}
That test will pass with Grails 2.4.2.
I hope that helps.
I upgrade to Grails 2.3 recently and try to migrate all old tests to spock integration test. But it fails at cleanup because my test is non-transactional. The Grails doc says test can be non-transactional, but we need to handle it manually, but it seems not quite right here. as I am getting this error in every integration test extending IntegrationSpec
java.lang.IllegalStateException: Cannot deactivate transaction synchronization - not active
at grails.test.spock.IntegrationSpec.cleanup(IntegrationSpec.groovy:72)
A simple test like this would throw that error:
import grails.test.spock.IntegrationSpec
public class DummySpec extends IntegrationSpec {
static transactional = false
def setup() {
}
def cleanup() {
}
def testDummy() {
expect:
1 == 1
}
}
I ran into this too! Pretty sure its a grails bug... I submitted a jira and a patch.
The error is thrown because the code in grails.test.spock.IntegrationSpec does not check for interceptor.isTransactional() before calling interceptor.destroy()
def cleanup() {
perMethodRequestEnvironmentInterceptor?.destroy()
perMethodTransactionInterceptor?.destroy() //breaks :(
}
...
private GrailsTestTransactionInterceptor initTransaction() {
def interceptor = new GrailsTestTransactionInterceptor(applicationContext)
if (interceptor.isTransactional(this)) interceptor.init() //also need for destroy()
interceptor
}
My fix was to add this code:
def cleanup() {
perMethodRequestEnvironmentInterceptor?.destroy()
destroyTransaction(perMethodTransactionInterceptor)
}
...
private void destroyTransaction(GrailsTestTransactionInterceptor interceptor){
if (interceptor?.isTransactional(this)) interceptor.destroy()
}
To work around for now, you can just create your own com.myname.IntegrationSpec with the patched code and extend that instead of grails.test.spock.IntegrationSpec. Not ideal... but it works :)
Grails 2.3 ships by default with Spock. Just remove your own defined spock dependency make sure to import grails.test.spock.IntegrationSpec and it should work.
I'm attempting to setup a testing scenario where I can publish a JAR of tests that will run the same sets of tests 95% of the time but there will be 5% of the tests that need to either override or stop a feature in the parent class. Is it possible to override parent specifications?
class ParentSpec extends Specification {
def "goto home page"() {
given:
to NormalHomePage
expect:
at NormalHomePage
}
}
... in a separate project that brings in the dependency for the ParentSpec
class ChildSpec extends ParentSpec {
#Override
def "goto home page"() {
given:
to SpecificHomePage
expect:
at SpecificHomePage
}
}
Is there something that I can do to either do this or simulate this?
Overriding feature methods isn't currently supported. With some effort, it would be possible to write an extension that skips the "super" method.
I'm learning groovy / grails, and writing my first integration test.
It's currently failing with:
groovy.lang.MissingMethodException: No
signature of method:
com.mangofactory.scurry.User.save() is
applicable for argument types: ()
values: []
My test isn't doing anything fancy:
class UserEventControllerTests extends ControllerUnitTestCase {
protected void setUp() {
super.setUp()
}
protected void tearDown() {
super.tearDown()
}
void testAddingAUser()
{
def user = new User(emailAddress: "martypitt#test.com")
user.save()
}
}
Saving the entity works fine when I do it through the scaffolded pages provided by grails.
What have I missed?
If you want it to be an integration tests it shouldn't extend one of the unit test base classes, so change it to
class UserEventControllerTests extends GroovyTestCase {
...
}
and make sure it's in test/integration, not test/unit.
But it looks like you want to test a controller (it's called UserEventControllerTests) which should extend ControllerUnitTestCase. If that's the case then you should be doing unit tests, but mocking the domain layer (using mockDomain and others) since you want to focus on controller logic, not persistence. Test domain classes in proper integration tests using a database.
This is all described in chapter 10 of the docs: http://grails.org/doc/latest/
I am having problems when using dependency injection with Services in Grails.
class ExampleService{
def example2Service
def example3Service
def method1(){
def result = example2Service.method2()
}
}
class ExampleService{
def example3Service
def method2(){
def result = example3Service.method3()
return result
}
}
class Example3Service{
def method3(){
return true
}
}
Basically in Example2Service, I am getting a Null Pointer Exception when trying to call method3 in Example3Service.
I would appreciate any help than anybody can give me with this issue
thanks
Dependency Injection needs to be initialized. (The same applies to other kinds of runtime meta programming, like augmenting Domain classes with their save() and validate() methods.)
A Grails application will be initialized when
being run from the grails run-app command
being run after having been deployed to a web server
being run from the grails test-app command (integration tests, only; unit tests do not trigger initialization).
Involved classes are not initialized when
executing a single Groovy file (i.e., by using groovy, groovysh, or groovyConsole)
or when executing a unit test.
The following as an integration test should work:
class Test2ServiceTests extends GroovyTestCase {
def test2Service
void testMethod2() {
assert test2Service.method2() == true
}
}