Grails Unit testing a function with session object - unit-testing

I having a Controller like
def testFunction(testCommand cmdObj) {
if (cmdObj.hasErrors()) {
render(view: "testView", model: [cmdObj:cmdObj])
return
} else {
try {
testService.testFunction(cmdObj.var1, cmdObj.var2, session.user.username as String)
flash.message = message(code: 'message')
redirect url: createLink(mapping: 'namedUrl')
} catch (GeneralException error) {
render(view: "testView", model: [cmdObj:cmdObj])
return
}
}
}
For the above controller function I having a Unit test function like:
def "test function" () {
controller.session.user.username = "testUser"
def testCommandOj = new testCommand(
var1:var1,
var2:var2,
var3:var3,
var4:var4
)
testService service = Mock(testService)
controller.testService = service
service.testFunction(var2,var3,var4)
when:
controller.testFunction(testCommandOj)
then:
view == "testView"
assertTrue model.cmdObj.hasErrors()
where:
var1 | var2 | var3 | var4
"testuser" | "word#3" | "word#4" | "word#4"
}
When running this test function I getting the error like Cannot set property 'username' on null object, means I couldn't able to set up the session object. Can someone help to fix this. Thanks in advance

Since you are doing the Grails controller's unit test, you can directly assign the variables into the session object as you do for params this way in your setup: block. I recommend you to just assign the User object in session first and then it will be fine: I have slightly modified your code:
def "test function" () {
setup:
User user = new User(username:'requiredUserName').save(flush:true,failOnError:true)
session.user = user
def testCommandOj = new testCommand(
var1:var1,
var2:var2,
var3:var3,
var4:var4
)
testService service = Mock(testService)
controller.testService = service
service.testFunction(var2,var3,var4)
when:
controller.testFunction(testCommandOj)
then:
view == "testView"
assertTrue model.cmdObj.hasErrors()
where:
var1 | var2 | var3 | var4
"testuser" | "word#3" | "word#4" | "word#4"
}
This should be working fine now.The only problem was you did not assign the User object in session.

Related

How to get the currentUser provided by spring security in Grails 2 unit testing

Hi guys i am on trouble about getting the current user provided by spring.
Here's my unit test code
void "Test if adding project will sucess"() {
given:
def createProjectMock = mockFor(UserService)
createProjectMock.demand.createNewProject { Map projectMap ->
return true
}
controller.userService = createProjectMock.createMock()
when: "saveProject is execute"
controller.saveProject()
then: "page will to the list to view the saved project"
response.redirectedUrl == '/user/index2'
}
Here's my controller
def saveProject(ProjectActionCommand projectCmd) {
def currentUser = springSecurityService.currentUser
if (projectCmd.hasErrors()) {
render view: 'createProject', model: [projectInstance: projectCmd, user:currentUser]
} else {
def getProjectMap = [:]
getProjectMap = [
projectName: params.projectName,
user: currentUser
]
def saveProject = userService.createNewProject(getProjectMap)
if (saveProject) {
redirect view: 'index2'
} else {
render 'Error upon saving'
}
}
}
And here's my service
Project createNewProject(Map projectMap){
def createProject = new Project()
createProject.with {
projectName = projectMap.projectName
user = projectMap.user
}
createProject.save(failOnError:true, flush: true)
}
And i always getting this error:
Cannot get property 'currentUser' on null object.
Hope you can help me. Thanks
Cannot get property 'currentUser' on null object.
means that you haven't mocked springSecurityService. Let's do it in setup section (I assume it may be useful also in other methods in this class):
def springSecurityService
def setup() {
springSecurityService = Mock(SpringSecurityService)
controller.springSecurityService = springSecurityService
}
At this point your code is going to work. However remember that you can always mock also the actual logged user and test it at any point:
User user = Mock(User)
springSecurityService.currentUser >> user

Controller always null in Spock unit test using Grails 2.5.1

I am new using Grails 2.5.1. I need to run some unit and integration test but I can't make them work.
My domain class is:
class Role {
String roleName
Role(String _roleName) {
roleName = _roleName
}
static constraints = {
roleName(blank: false, nullable: false)
}
String toString(){
"$roleName"
}
}
My controller class is:
class RoleController {
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond Role.list(params), model:[roleInstanceCount: Role.count()]
}
def show(Role roleInstance) {
respond roleInstance
}
def create() {
respond new Role(params)
}
...
}
Under test/unit I have the class RoleControllerSpec:
import grails.test.mixin.*
import spock.lang.*
#TestFor(RoleController)
#Mock(Role)
class RoleControllerSpec extends Specification {
def 'index action: 1 role'() {
setup:
roleInstance.save()
expect:
controller.index() == [roleInstanceList: [roleInstance], roleInstanceTotal: 1]
where:
roleInstance = new Role(roleName: "Role1")
}
def "create action"() {
setup:
controller.params.roleName = roleName
when:
def model = controller.create()
then:
model.roleInstance != null
model.roleInstance.roleName == roleName
where:
roleName = "Role1"
}
}
When I run the test with test-app -unit RoleController it give me the following exceptions:
|Configuring classpath
.
|Environment set to test
....................................
|Running without daemon...
..........................................
|Compiling 1 source files
.
|Running 2 unit tests...
|Running 2 unit tests... 1 of 2
Failure: |
index action: 1 role(accessmanagement.RoleControllerSpec)
|
Condition not satisfied:
controller.index() == [roleInstanceList: [roleInstance], roleInstanceTotal: 1]
| | | |
| null false Role1
role(RoleControllerSpec.groovy:17)
|Running 2 unit tests... 2 of 2
Failure: |
create action(accessmanagement.RoleControllerSpec)
|
java.lang.NullPointerException: Cannot get property 'roleInstance' on null object
at accessmanagement.RoleControllerSpec.create action(RoleControllerSpec.groovy:34)
|Completed 2 unit tests, 2 failed in 0m 6s
.Tests FAILED
|
Error |
Forked Grails VM exited with error
It seems that controller is null in my tests.
In the first test controller.index() is null. In the second test def model = controller.create() is not creating the object, then when I try to access model.roleInstance it cannot get the property.
Any idea would be appreciated.
Thanks!
Since you are using respond and not simply returning a map from the controller, you need to check the model property
def 'index action: 1 role'() {
setup:
Role roleInstance = new Role(roleName: "Role1").save()
when:
controller.index()
then:
model == [roleInstanceList: [roleInstance], roleInstanceTotal: 1]
}
I would suggest you read the documentation on testing controllers https://grails.github.io/grails-doc/2.5.x/guide/testing.html#unitTestingControllers

Grails Controller Unit Test doesn't render page to response.text

My env configs: Java 1.7u51, Grails 2.3.7
I'm trying to assert response.text in Controller Test but it always brings "".
What's happening?
This is my UserController
class UserController {
def index() {
flash.errors = "$params.secret"
render view: "index", model: [model: params.toModel,
text: params.username]
}
}
This is /user/index.gsp file
${text}
This is my Specification
#TestFor(UserController)
class UserControllerSpec extends Specification {
def setup() {
}
def cleanup() {
}
void "test something"() {
given:
params.username = "USERNAME"
params.password = "SECRET"
params.toModel = "Model"
when:
controller.index()
then:
flash.errors
view == "/user/index"
params.username == response.text
model.model == params.toModel
}
}
And test report is:
Failure: |
test something(teste.UserControllerSpec)
|
Condition not satisfied:
params.username == response.text
| | | | |
| USERNAME | | ""
| | org.codehaus.groovy.grails.plugins.testing.GrailsMockHttpServletResponse#46f29a61
| false
| 8 differences (0% similarity)
| (USERNAME)
| (-------)
[username:USERNAME, password:SECRET, toModel:Model]
It is only the case of a template rendering where the content of the template is directly rendered to response as String. Hence response.text can only be used when a template is rendered unlike in this case where a view is being rendered.
In order to test rendering a view, GroovyPageUnitTestMixin has to be used as below:
import grails.test.mixin.TestMixin
import spock.lang.Specification
import grails.test.mixin.web.GroovyPageUnitTestMixin
#TestMixin(GroovyPageUnitTestMixin)
class UserControllerSpec extends Specification {
def controller
def setup(){
controller = testFor(UserController)
}
void "test something"() {
given:
params.username = "USERNAME"
params.password = "SECRET"
params.toModel = "Model"
when:
controller.index()
then:
flash.errors
view == "/user/index"
model.model == params.toModel
//method provided by mixin which mimics render method in
//controller. Make sure model is also passed in the map arg
//since view uses model.text
render(view: "/user/index", model: model) == 'USERNAME'
}
}
Note:
#TestFor is replaced with the Mixin in the test. Therefore, controller has to be mocked as seen in setup() using testFor() method.
render() can also be used to test template rendering with the key template similar to the usage of key view in the map argument.

Unit Test Grails with Service

I'm trying to do a test on controller that uses 3 Domains and a service to perform persistence, when I use these values ​​in view he is saving normally, but in my unit test does not pass validation, I do not understand why . If someone who has been there can help me, I do not know if the Mock I'm doing is correct, I followed the examples in the documentation oficial .
thats the error message:
junit.framework.AssertionFailedError: expected:<1> but was:<0>
Thats my code for Test:
#TestFor(UsuarioController)
#Mock([SecRole, UsuarioService, Usuario, Cliente, Secuser])
#TestMixin(ControllerUnitTestMixin)
class UsuarioTests {
private def usuarioCommand
private def service
#Before
void setUp() {
usuarioCommand = mockCommandObject(UsuarioCommand)
service = mockFor(UsuarioService)
}
#Test
void testCadastrarUsuarioCorreto() {
usuarioCommand.perfil = 2
usuarioCommand.nome = "Michael Swaltz"
usuarioCommand.cpf = "381.453.718-13"
usuarioCommand.email = "michael.s#mail.com"
usuarioCommand.login = "login"
usuarioCommand.senha = "senha"
usuarioCommand.senhaRepeat = "senha"
assertTrue( usuarioCommand.validate() );
controller.usuarioService = service
controller.create(usuarioCommand)
assertEquals(1, Usuario.count())
}
This is my controller action:
def create = { UsuarioCommand usuario ->
if(!params.create) return
if(!usuario.hasErrors()) {
def secuser = new Secuser(username: usuario.login, password: usuario.senha, senha: usuario.senhaRepeat, enabled: true)
def user = new Usuario(nomeUsuario: usuario.nome, email: usuario.email, cpf: usuario.cpf, idNivelAcesso: usuario.perfil)
def cliente = Cliente.findByUsuario( session.usuario )
user.setIdCliente(cliente)
def secrole = SecRole.get( usuario.perfil )
try{
usuarioService.save(user, secuser, secrole)
flash.message = "Usuário ${usuario.nome} cadastrado.".toString()
redirect (action: 'list')
}catch(ValidationException ex) {
StringBuilder mensagem = new StringBuilder();
ex.errors.fieldErrors.each { FieldError field ->
mensagem.append("O campo ").append( field.field )
.append(" da classe ")
.append( field.objectName )
.append(" com o valor ")
.append( field.rejectedValue )
.append(" não passou na validação.")
.append("\n")
}
flash.error = mensagem.toString()
return [usr: usuario]
}catch(ex) {
flash.error = ex.message
render "Erro"
//return [usr: usuario]
}
}else {
usuario.errors.allErrors.each { println it }
render "Erro"
//return [usr: usuario]
}
}
mockFor would give you back a mock control. You have to explicitly call createMock() on the mock control to get the actual mocked object.
service = mockFor(UsuarioService).createMock()
Have a look at "Mocking Collaborators" from the same link you referred. The test can be optimized if you still face an issue.
similar example and one here.
You need to set an expectation on the UsarioService to say what will be returned when usarioService.save(...) is called.
Before getting to that point, you need to say in the test
mockUsarioService.createMock() which will create the actual instance of the mock object, that's what you will pass to the controller usarioService attribute. Copied the code below from the Grails documenation. http://grails.org/doc/1.1/guide/9.%20Testing.html
String testId = "NH-12347686"
def otherControl = mockFor(OtherService)
otherControl.demand.newIdentifier(1..1) {-> return testId }
// Initialise the service and test the target method.
def testService = new MyService()
testService.otherService = otherControl.createMock()

Grails 2.0: Issue testing flash.message

I have a unit test for my UserController but since upgrading to Grails 2.0, the flash variable always seems to return an emtpy map with no message.
Here are some code snippets of the UserControllerTests:
#TestFor(UserController)
#Mock(User)
class UserControllerTests {
...
void testSaveSucceeds() {
params.userName = 'Joe'
...
controller.save()
assert null != flash.message
assert '/user/list' == response.redirectedUrl
}
}
In UserController:
def save = {
def userInstance = new User(params)
if (userInstance.validate()) {
flash.message = message(code: 'default.created.message', args: [userInstance.userName ])
...
}
But my test result is as follows:
assert null != flash.message
| | |
| [:] null
false
I have tried as an integration test as well because otherwise the response was null as weill but it did not fix the flash issue. The same problem also exists with view and model.
What am I missing? Any help highly appreciated.
Regards
Jonas
EDIT:
Here's a weird scenario:
My controller has the following:
def test = {
flash.message = "Message"
}
def save = {
flash.message = "Message"
}
My Test looks like that:
void testSaveSucceeds() {
controller.save()
println ">>> ${flash}"
controller.test()
println ">>> ${flash}"
}
The output like that:
>>> [:]
>>> [message:Message]
Interesting to mention is also that the debugger in IntelliJ stops at a breakpoint in the test() action but not in save()
HOW can that be????
Regards
Jonas
For me it means that userInstance.validate() return false ie the validation failed.