Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock private methods in controller in grails 2.2.4

I have a private method which was mocked in grails 1.3.7 using metaclass but now that I upgraded grails version to 2.2.4, the same mocking fails.

Method to test has a call to private method

   private def MyPrivateMeth1(def arg1, def arg2) {
...
}

Mocking is something like this

MyController.metaClass.private.MyPrivateMeth1 = { a, b ->
... 
}
like image 443
user1298426 Avatar asked Sep 21 '13 15:09

user1298426


2 Answers

Try using the @TestFor annotation, which will give you a controller variable. You can then alter the metaclass of that, as well as incorporating Kamil Mikolajczyk and araxn1d's suggestions. So, your whole test should probably look like this:

@TestFor(MyController) 
class MyControllerTests { 

    setup() {
        controller.metaClass.MyPrivateMeth1 = {def arg1, def arg2 -> 
            //you can make your mocked method return whatever you wish here
            return [key1: "foo", key2: "bar"] 
        }
    }
    void testForSomething() {
        //Some code here that invokes an action or two in your controller which in turn invokes the private method
    }
}

Make sure to have def (or String, Long, or whatever declaration you use) on the arguments of your mock method precisely as they are on the actual private method in the controller, or your test will try to use the class's normal private method first.

Here's a similar test in Spock:

import spock.lang.Specification
import spock.lang.Unroll
import grails.test.mixin.*
import org.junit.*
@TestFor(MyController) 
class MyControllerSpec {

    def "test that thing"() {
        setup:
            controller.metaClass.MyPrivateMeth1 = {def arg1, def arg2 -> return someOutput }
        expect:
            controller.someAction() == expectedRender
        where: 
            someOutput                              | expectedRender
            [key1: "foo", key2: "bar"]              | "expected render from controller"
    }
}
like image 53
jonnybot Avatar answered Oct 01 '22 13:10

jonnybot


It seems that you need to declare types of closure arguments (its 100% if that arguments have actual types, for example Long, but not sure about def, but you need to try):

MyController.metaClass.MyPrivateMeth1 = { def a, def b -> ... }
like image 40
rxn1d Avatar answered Oct 01 '22 15:10

rxn1d