11

I am trying to write unit tests for a service which use grailsApplication.config to do some settings. It seems that in my unit tests that service instance could not access the config file (null pointer) for its setting while it could access that setting when I run "run-app". How could I configure the service to access grailsApplication service in my unit tests.

class MapCloudMediaServerControllerTests {

    def grailsApplication

    @Before
    public void setUp(){
        grailsApplication.config= 
        '''
   video{
   location="C:\\tmp\\"  // or shared filesystem drive for a cluster

    yamdi{
        path="C:\\FFmpeg\\ffmpeg-20121125-git-26c531c-win64-static\\bin\\yamdi"  
         }

    ffmpeg  {
        fileExtension = "flv"  // use flv or mp4
        conversionArgs = "-b 600k -r 24 -ar 22050 -ab 96k"
        path="C:\\FFmpeg\\ffmpeg-20121125-git-26c531c-win64-static\\bin\\ffmpeg"
        makethumb = "-an -ss 00:00:03 -an -r 2 -vframes 1 -y -f mjpeg"
    }

    ffprobe {
        path="C:\\FFmpeg\\ffmpeg-20121125-git-26c531c-win64-static\\bin\\ffprobe" 
        params=""
    }

    flowplayer {
        version = "3.1.2" 
    }

    swfobject {
        version = "" 

    qtfaststart {
        path= "C:\\FFmpeg\\ffmpeg-20121125-git-26c531c-win64-static\\bin\\qtfaststart" 
    } 
}   '''
    }

@Test
    void testMpegtoFlvConvertor() {

        log.info "In test Mpg to Flv Convertor function!"

        def controller=new MapCloudMediaServerController()
        assert controller!=null

        controller.videoService=new VideoService()  
        assert controller.videoService!=null

        log.info "Is the video service null? ${controller.videoService==null}"

        controller.videoService.grailsApplication=grailsApplication

        log.info "Is grailsApplication null? ${controller.videoService.grailsApplication==null}"

        //Very important part for simulating the HTTP request
        controller.metaClass.request = new MockMultipartHttpServletRequest()
        controller.request.contentType="video/mpg"
        controller.request.content= new File("..\\MapCloudMediaServer\\web-app\\videoclips\\sample3.mpg").getBytes()

        controller.mpegtoFlvConvertor()

        byte[] videoOut=IOUtils.toByteArray(controller.response.getOutputStream())
        def outputFile=new File("..\\MapCloudMediaServer\\web-app\\videoclips\\testsample3.flv")
        outputFile.append(videoOut) 
    }
}
Ken Liu
  • 22,503
  • 19
  • 75
  • 98
Reza
  • 739
  • 1
  • 10
  • 24
  • You have the TestFor or any annotation in this test? Do not redeclare grailsApplication, the mock comes with the annotation. See `GrailsUnitTestMixin`. –  Dec 12 '12 at 19:39
  • yes It has @TestFor annotation. I removed the "def grailsApplication" but got the message null on grailsApplication object. BTW I am using Grail 2.1. – Reza Dec 12 '12 at 21:41
  • Can you post the stacktrace? Also, I don't have sure that you can declare config like this, because it's a instance of ConfigObject. I will make a test and see if you will need to use the ConfigSlurper. –  Dec 12 '12 at 21:50
  • I think it could not parse the config data. This is the error message : Cannot cast object ' video{ ...... } } ' with class 'java.lang.String' to class 'groovy.util.ConfigObject' – Reza Dec 12 '12 at 22:43
  • See my edit, you need to use ConfigSlurper in this case. –  Dec 12 '12 at 23:01

3 Answers3

19

If you use @TestFor Grails (2.0) already mock grailsApplication for you, just set your configs, but do not declare the grailsApplication. Doing that overrides the mocked instance.

@TestFor(MyService)
class MyServiceTests {

  @Before
  public void setUp() {
    grailsApplication.config.something = "something"
  }

  @Test
  void testSomething() {
    MyService service = new MyService()
    service.grailsApplication = grailsApplication
    service.doSomething()
  }


}

EDIT:

You declared a String, to add to config you must parse this. See here an example.

Basically you use the ConfigSlurper().parse() to get a ConfigObject, and use grails.config.merge() to add the contents to the config.

  • I did the service unit test before and it's working. Now I used that service in a controller. I want to test the controller which uses that service. It seems that I could not set the grailsApplication(for the service) to test the controller functionality. Any suggestions? – Reza Dec 12 '12 at 18:43
  • Just create the service like this example and directly set in the instance of your controller. –  Dec 12 '12 at 18:45
  • I did the same way you mentioned but got the message "Cannot set property 'config' on null object". – Reza Dec 12 '12 at 19:15
  • I also have problems with this since groovy.lang.MissingPropertyException: No such property: grailsApplication for class: MyService – Rafael Nov 13 '14 at 12:24
5

Constructing grailsApp using DefaultGrailsApplication would work.

class ZazzercodeUnitTestCase extends GrailsUnitTestCase {
    def grailsApplication = new org.codehaus.groovy.grails.commons.DefaultGrailsApplication()
    def chortIndex= grailsApplication.config.zazzercode.chortIndex
}
prayagupa
  • 30,204
  • 14
  • 155
  • 192
1

Go to http://ilikeorangutans.github.io/2014/02/06/grails-2-testing-guide

Grails’ config is usually accessed via an injected instance of GrailsApplication using the config property. Grails injects GrailsApplication into unit tests, so you can access it directly:

@TestMixin(GrailsUnitTestMixin)
class MySpec extends Specification {        
    private static final String VALUE = "Hello"
    void "test something with config"() {
        setup:
        // You have access to grailsApplication.config so you can 
        //modify these values as much as you need, so you can do
        grailsApplication.config.myConfigValue = VALUE

        assert:             
        grailsApplication.config.myConfigValue == VALUE
    }

}
eHayik
  • 2,981
  • 1
  • 21
  • 33