AnthonyMDev
AnthonyMDev

Reputation: 1506

Grails Integration Test - Null object for getBean()

I cannot figure out why my integration tests here are throwing exceptions.

Integration Test ##

package sample

import grails.test.mixin.*
import org.junit.*

/**
 * See the API for {@link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
 */
@TestFor(UserController)
class UserControllerTests extends GroovyTestCase {

 User user
 UserController uc

 void setUp() {
    //Save a User
     user = new User(userName: "User1", firstName: "User1FN", lastName: "User1LN")
     user.save()

     //Set up UserController
     uc = new UserController()
 }

 void tearDown() {
     user.delete()
 }

 /**
  * Test the UserController.handleLogin action.
  * 
  * If the login succeeds, it will put the user object into the session.
  */

 void testHandleLogin() {
     //Setup controller paramaters
     uc.params.userName = user.userName

     //Call the action
     uc.handleLogin()

     //if the action functioned correctly, it put a user object into the session
     def sessUser = uc.session.user
     assert sessUser
     assertEquals("Expected ids to match", user.id, sessUser.id)
     //And the user was redirected to the Todo Page
     assertTrue uc.response.redirectedUrl.startsWith("/todo")
 }

 /**
  * Test the UserController.handleLogin action.
  * 
  * If the login fails, it will redirect to login and set a flash message.
  * 
  */

 void testHandleLoginInvalidUser() {
    //Setup controller parameters
     uc.params.userName = "Invalid_Name"

     //Call the action
     uc.handleLogin()
     assertEquals "/user/login", uc.response.redirectedUrl
     def message = uc.flash.message
     assert message
     assert message.startsWith("User not found")
 }

 /*
  * Test the UserController.logout action
  * 
  * If the logout action succeeds, it will remove the user object from the session.
  */
 void testLogout (){
     //Make a user logged into session
     uc.session.user = user


     //Call the action
     uc.logout()
     def sessUser = uc.session.user
     assertNull ("Expected session user to be null", sessUser)
     assertEquals "/user/login", uc.response.redirectedUrl
 }

}

Console output for test

| Loading Grails 2.2.3
| Configuring classpath.
| Environment set to test.....
| Packaging Grails application.....
| Packaging Grails application.....
| Compiling 1 source files.
| Running 3 integration tests... 1 of 3
| Running 3 integration tests... 2 of 3
| Failure:  testHandleLoginInvalidUser(sample.UserControllerTests)
|  java.lang.NullPointerException: Cannot invoke method getBean() on null object
    at grails.test.mixin.web.ControllerUnitTestMixin$_mockController_closure3.doCall(ControllerUnitTestMixin.groovy:304)
    at grails.test.mixin.web.ControllerUnitTestMixin.mockController(ControllerUnitTestMixin.groovy:311)
| Failure:  testHandleLoginInvalidUser(sample.UserControllerTests)
|  java.lang.NullPointerException: Cannot invoke method delete() on null object
    at sample.UserControllerTests.tearDown(UserControllerTests.groovy:25)
| Running 3 integration tests... 3 of 3
| Failure:  testLogout(sample.UserControllerTests)
|  java.lang.NullPointerException: Cannot invoke method getBean() on null object
    at grails.test.mixin.web.ControllerUnitTestMixin$_mockController_closure3.doCall(ControllerUnitTestMixin.groovy:304)
    at grails.test.mixin.web.ControllerUnitTestMixin.mockController(ControllerUnitTestMixin.groovy:311)
| Failure:  testLogout(sample.UserControllerTests)
|  java.lang.NullPointerException: Cannot invoke method delete() on null object
    at sample.UserControllerTests.tearDown(UserControllerTests.groovy:25)
| Failure:  sample.UserControllerTests
|  java.lang.NullPointerException: Cannot invoke method isActive() on null object
    at grails.test.mixin.support.GrailsUnitTestMixin.shutdownApplicationContext(GrailsUnitTestMixin.groovy:234)

| Completed 3 integration tests, 5 failed in 980ms

Upvotes: 1

Views: 1270

Answers (1)

Burt Beckwith
Burt Beckwith

Reputation: 75671

You're using unit test annotations in an integration test - that will cause lots of problems. In general when doing integration tests you extend GroovyTestCase if you want to use JUnit3-style tests, or nothing and use JUnit4 annotations, or use Spock and extend IntegrationSpec.

As for the NPEs, whether you're using proper unit tests or integration tests, you need to manage the controller's dependencies yourself since you explicitly create it with new and don't access it as a pre-wired Spring bean. But the integration test does support dependency injection, so just add fields in your test for whatever you need in the controller, and in setUp or in individual methods you can set those beans in the controller, e.g.

class UserControllerTests extends GroovyTestCase {

   def grailsApplication
   def someSpringBean
   def someOtherSpringBean
   private UserController uc = new UserController()

   protected void setUp() {
      super.setUp()
      user = new User(userName: "User1", firstName: "User1FN", lastName: "User1LN").save()

      //Set up UserController
      uc.applicationContext = grailsApplication.mainContext
      uc.someSpringBean = someSpringBean
      uc.someOtherSpringBean = someOtherSpringBean
   }
...

Also note that you don't need to cleanup your data in tearDown() - integration tests run in a transaction that's rolled back at the end of the test method.

Upvotes: 4

Related Questions