Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test a controller that has a @Mixin of a Basecontroller

Tags:

grails

spock

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

like image 219
Anthony Avatar asked Feb 16 '23 07:02

Anthony


2 Answers

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.

like image 76
dmahapatro Avatar answered Feb 18 '23 19:02

dmahapatro


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).

like image 23
Tomasz Kalkosiński Avatar answered Feb 18 '23 19:02

Tomasz Kalkosiński