I have used manually written as well as Grails generated Unit tests for this command object:
package myapp
#grails.validation.Validateable
class SearchCommand {
String basisBuild
String buildToSearch
static constraints = {
basisBuild(blank: false)
}
}
After having my hand written unit test fail I used Grails:
create-unit-test myapp.SearchCommand
I filled in the Unit Test, and made an assertion that should pass per documentation on mocked constraints:
package myapp
import static org.junit.Assert.*
import grails.test.mixin.*
import grails.test.mixin.support.*
import org.junit.*
#TestMixin(GrailsUnitTestMixin)
class SearchCommandTests {
void setUp() {
mockForConstraintsTests(SearchCommand)
}
void tearDown() {
// Tear down logic here
}
void testSomething() {
SearchCommand commandUnderTest = new SearchCommand()
commandUnderTest.validate(basisBuild: "")
assertEquals "blank", commandUnderTest.errors['basisBuild']
}
}
Why am I getting this failure?
grails> test-app
| Running 9 unit tests... 9 of 9
| Failure: testSomething(com.siemens.soarian.sf.gap.SearchCommandTests)
| java.lang.AssertionError: expected:<blank> but was:<null>
at org.junit.Assert.fail(Assert.java:93)
I believe I found the grails supported way to unit test Command objects in grails 2.0. You need to use mockCommandObject provided by the ControllerUnitTestMixin.
Credit to Erik
http://www.jworks.nl/2012/04/12/testing-command-objects-in-grails-2-0/
EDIT
Using validate() appropriately and mockForConstraintsTest should work if the patch mentioned in the existing Grails bug is in place (Thanks to #codelark for bringing that up). In order to test the command object from a Web App standpoint (using controller) the below information would be helpful.
Test Command Object Using Controller action:-
A command object is only deemed as such when it is used as a parameter in one of the action method inside a controller. Refer Command Objects (Warning NOTE).
Use SearchCommand in an action method, you should be able to assertEquals.
Sample:
void testSomething() {
YourController controller = mockController(YourController) //Or instantiate
SearchCommand commandUnderTest = new SearchCommand ()
//Note the usage here. validate() does not take parameters
commandUnderTest.basisBuild = ''
commandUnderTest.validate()
//Call your action
controller.searchCommandAction(commandUnderTest)
assert response.text == 'Returned'
assertEquals "blank", commandUnderTest.errors['basisBuild']
}
YourController's action:-
def searchCommandAction(SearchCommand sc){
render "Returned"
}
Note:
With out the patch from the grails bug we see the below error in #Grails 2.1.4, 2.2.0 & 2.2.1
I get an error when I only correct the validation and use mockForConstraintTests without using controller action:
You are using the validate method incorrectly. You never set the field on the class, so the field is null, not blank. Try changing your test as follows:
void testSomething() {
SearchCommand commandUnderTest = new SearchCommand()
commandUnderTest.basisBuild = ""
assertFalse commandUnderTest.validate()
assertEquals 'blank', commandUnderTest.errors['basisBuild']
}
Edit: There is also a grails bug when testing command classes that use the #Validatable annotation. There are some workarounds in the bug commentary.
Related
In Grails 3.1.12, I want to unit test a service:
#Transactional
class PlanService {
List<Plan> getPlans(Map params) {
def currentUser = (User)springSecurityService.getCurrentUser()
return Plan.findAllByCompany(currentUser.employer, params)
}
}
Like this:
#TestFor(PlanService)
#Mock([Plan, User, Company])
class PlanServiceSpec extends Specification {
void "Retrieve plan from the current user"() {
setup:
// create and save entities here
when: "the plans are retrieved"
def params = null
def plans = service.getPlans(params)
then: "the result should only include plans associated to the current user's company"
plans.size() == 2
}
Running the test from the console:
grails> test-app my.PlanServiceSpec -unit
Fails with:
my.FundingPlanServiceSpec > Retrieve plan from the current user FAILED
java.lang.IllegalStateException at PlanServiceSpec.groovy:48
and in the test report (HTML):
java.lang.IllegalStateException: No transactionManager was specified.
Using #Transactional or #Rollback requires a valid configured transaction manager.
If you are running in a unit test ensure the test has been properly configured
and that you run the test suite not an individual test method.
Now if I comment out the #Transactional annotation in the service, the test passes, but that's not the intended implementation. I am able to work around the problem by mocking the transaction manager:
service.transactionManager = Mock(PlatformTransactionManager) {
getTransaction(_) >> Mock(TransactionStatus)
}
But this seems very awkward, if not wrong.
Is there some incantation I forgot to invoke?
EDIT: looks similar to an old bug, but it's been closed more than a year.
Have you tried what a comments says that fixes the problem? If not, try to annotate the test class with:
#TestMixin(DomainClassUnitTestMixin)
and then:
service.transactionManager = getTransactionManager()
Was getting the same error in grails 3.3.2 when trying to test transactional service.
adding DataTest interface solved the issue for me.
class HelloServiceSpec extends Specification implements ServiceUnitTest<HelloService>, DataTest {
}
I am new in Grails, I want to write unit tests for services using Spock. However I have the following issue.
import grails.transaction.Transactional
#Transactional
class BService {
boolean createB(){
return true
}
...
}
For this class I wrote the following test:
class BServiceTest extends Specification {
def "test createB"(){
given:
def service = new BService()
when:
def boolean temp
temp = service.createB()
then:
temp == true
}
}
The error I am getting when I run this test is the following:
java.lang.IllegalStateException: No transactionManager was specified. Using #Transactional or #Rollback requires a valid configured transaction manager. If you are running in a unit test ensure the test has been properly configured and that you run the test suite not an individual test method.
and it shows in GrailsTransactionTemplate.groovy:60
I would really appreciatie if anyone can give me a hint.
Add a #TestFor(BService) annotation to your unit test and use the instance of the service that it automatically provides. See http://grails.github.io/grails-doc/3.0.x/guide/testing.html for more information on testing.
Thank you ataylor for your reply. However I did a mistake, so I am now ansewring my own question.
First of all, the name conversion is wrong. When I create a service in grails there is automatically set a unit-test for this, so in that case I would have:
#TestFor(BService)
class BServiceSpec extends Specification {
def setup() {
User u = new User(1)
u.save()
}
def cleanup() {
}
def "test something"(){
}
}
In this case when I write a unit test, it runs.
The test that I had before was a functional test where I could not pass objects from the domain, so I had an error of the transactional manager.
As the title states, is it possible to have a unit test for a controller, and mock a tag lib?
As it stands, I have a User controller. Many of the actions use the
g.message(code: 'something.something')
call to set a message on the page.
#TestFor(UserController)
#Mock(User)
#TestMixin(GroovyPageUnitTestMixin)
class UserControllerSpec extends Specification
{
UserService userServiceMock = Mock(UserService)
def setup()
{
controller.userService = userServiceMock
}
def cleanup()
{
}
void "test manageDevice"()
{
given:
def g = mockTagLib(FormTagLib)
when:
controller.manageDevice()
then:
model.pageTitle == 'message.device'
}
With that code I'm trying to hit the controller action but because of the g.message, it's failing with an error saying that it can't set a value to null. Pretty much because it doesn't see the "g.message"
I'm a little unsure if my unit test needs written differently, or if I'm just missing something.
Any help would be great!
EDIT:
Some updates using messageSource:
void "test manageDevice"()
{
given:
messageSource.addMessage 'user.devices', request.locale, 'Manage Devices'
when:
controller.manageDevices()
then:
assertEquals model.pageTitle == 'user.devices', controller.flash.message
}
It seems to still be complaining because it doesn't have context of the "g" namespace on the controller. I'll note as well, I don't have context of 'addMessage' from messageSource. Not sure why, it should be there.
In the same controller, and many others, the only taglib we use in the controller scope is 'g' for the 'g.message' set in each action. The only other call that's being done, is one using the 'g' for a call like 'g.fixRedisIssue'
You can make a unit test for a controller with a mocked TagLib by including the necessary TagLib classes in the value of the grails.test.mixin.Mock annotation on the Spec class. For example, if you have the following TagLib:
(based on code in Grails documentation)
package org.grails.samples
class SimpleTagLib {
static namespace = 'g'
def hello = { attrs, body ->
out << "Hello ${attrs.name ?: 'World'}"
}
}
And you have the following controller:
package org.grails.samples
class SimpleController {
def flashHello() {
flash.message = g.hello()
}
}
You could test it with the following specification:
package org.grails.samples
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(SimpleController)
#Mock(SimpleTagLib)
class SimpleControllerSpec extends Specification {
void 'test flashHello'() {
when:
controller.flashHello()
then:
flash.message == 'Hello World'
}
}
If you have multiple classes to mock, you can specify them in an array argument to #Mock. So you can add any necessary tag libraries to UserControllerSpec by changing #Mock(User) to something like #Mock([User, FormTagLib, YourFixRedisIssueTagLib]). However, I'd be surprised if you actually did need to add FormTagLib because in my Grails testing it seems to be included by default.
As some further advice, some of the code you posted doesn't make any sense. Specifically:
assertEquals model.pageTitle == 'user.devices', controller.flash.message
Decide specifically what you want to test for and focus on writing the simplest code possible for that.
Also, based on your description of what's happening, I think that you're getting thrown off because your IDE is not properly integrated with Grails to see the g context.
Instead of returning the message text to the view from the controller, why not return the message code instead? For example, if you have something like this in your view:
<p>${flash.message}</p>
You can replace it with this:
<p><g:message code="${flash.code}" /></p>
And then set the code in the controller:
flash.code = "user.devices"
Then you'll be able to test the controller methods painlessly :)
I use the Grails Spring Security Plugin for my project and now want to unit test my code. I have the following code in my controller:
def index() {
redirect action: 'show', params: [id: springSecurityService.currentUser.id]
}
My Test Class has the following code:
void testIndex() {
controller.index()
assert "/user/list" == response.redirectedUrl
}
This test fails:
| Running 8 unit tests... 1 of 8
| Failure: testIndex(xxx.UserControllerTests)
| java.lang.NullPointerException: Cannot get property 'currentUser' on null object
at xxx.UserController.index(UserController.groovy:12)
at xxx.UserControllerTests.testIndex(UserControllerTests.groovy:19)
How can I authenticate a spring security user in a test case? How would you write the unit test?
You have to use functional tests for security. Unit tests use mocking but don't have plugins available, or a real request. Spring Security is implemented with a filter chain, so you need a real running server. If you use mocks, you're just testing the mocking.
For something this simple I wouldn't bother with complicated mocks, a straightforward
controller.springSecurityService = [currentUser:[id:1]]
would be sufficient.
It appears that your reference to springSecurityService is null. As long as you have a field in your controller named springSecurityService, it should be injected. Are you using it as a local variable only in your index method and did not declare it as a field?
My UserController is as follows:
class UserController {
/**
* Dependency injection for the springSecurityService.
*/
def springSecurityService
....
}
UPDATE
Based on your comments to this answer, you did declare a springSecurityService field in your controller. I took my working application and tried a test that mirrors yours with my controller method:
#TestFor(UserController)
class UserControllerTests {
void testSomething() {
controller.register()
}
}
I got a NullPointerException as well. From Burt's answer, (I did not know this), I think the springSecurityService instance is null in the contexts of the Unit Test execution.
I've written a Grails tag that is just a very thin wrapper around the Grails select tag
package com.example
class MyTagLib {
def listTrees = {attrs ->
List<TreeDto> allTrees = getMandatoryAttributeValue(attrs, 'trees')
out << g.select(from: allTrees)
}
}
I've wrtitten a unit test for this class, but when I run it, I get the following error when the last line is executed:
groovy.lang.MissingMethodException: No
signature of method:
com.example.MyTagLib.select() is
applicable for argument types:
(java.util.LinkedHashMap)
It seems like the reference to the grails tags in the g namespace are not available when running unit tests. I've tried creating an integration test instead, but this doesn't work either.
Is there a way to test test a tag that calls another tag without stubbing/mocking the output of that other tag?
You have to mock the grails taglib you are using and inject it via the metaClass mechanism.
protected void setUp() {
super.setUp()
mockTagLib(FormTagLib)
def g = new FormTagLib()
tagLib.metaClass.g = g
}