unit-testing grails tag - unit-testing

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
}

Related

In Grails spock test, how do I mock a custom taglib, called inside a custom taglib?

Okay, I have a custom taglib inside a custom taglib like so:
def preference = { attrs, body ->
def sliderTaglib = grailsApplication.mainContext.getBean('com.myCustom.sliderTagLib')
sliderTaglib.slider.call(attrs, body)
}
Since I am using grailsApplication.mainContext.getBean() , how do i mock that in my unit test? My test complains:
grails Error executing tag No bean named is defined...
I've tried various methods to mock it but to no avail. It functions correctly when I run-app though, it's just the test that fails. I'm using grails 2.3.9 and spock. :(
My test looks like this:
void "taglib should output a slider"() {
when:
def result = applyTemplate("""
<a:preference class='slider'/>
""")
then:
result == "<div class='slider'></div>"
}
You can mock the taglib by using
#TestMixin(GroovyPageUnitTestMixin)
class MultipleTagLibSpec extends Specification {
void "test multiple tags"() {
given:
mockTagLib(sliderTagLib)
expect:
// …
}
}
By the you should must not lookup the sliderTagLib bean in the application context. You simple call the taglib by calling the taglib-namespace.taglib-method.
E.g. the Grails taglibs are in the g namespace. Therefore use it like this.
def preference = { attrs, body ->
out << g.link(...)
// in your case
yourNamespace.slider(....)
}

Grails Unit Test Service MissingProperty 'log'

I want to run a unit test for a service. The method I want to test includes a some log.debug() statements. While the log property is injected at runtime, it does not seem to be injected in tests, so it throws groovy.lang.MissingPropertyException: No such property: log for class:
This is my unit test class:
#TestFor(ServiceUnderTest)
#Mock([ServiceUnderTest])
class ServiceUnderTestTests {
def test() {
def mock = [ mockedProp: [...] ] as ServiceUnderTest
def info = mock.doOperation()
assert ....
}
}
I've also tried adding MockUtils.mockLogging(ServiceUnderTest) but with no success.
How can I get the log property properly injected in my service class while in unit tests?
You do not have to have the test class annotated with #Mock([ServiceUnderTest]). #TestFor(ServiceUnderTest) detects its a service class and does all the mocking automatically. It also adds a service property to the test class that can be accessed in all the test methods and mocks the log property accordingly.
I think the problem why neither mocking nor explicit log mocking with MockUtils.mockLogging(ServiceUnderTest) does work in your case is the as coercion you are using in your test method code:
def mock = [ mockedProp: [...] ] as ServiceUnderTest
Groovy internally uses java.lang.reflect.Proxy to create a proxy descendant class from ServiceUnderTest. The proxy class does not see changes done to the ServiceUnderTest meta class like the added log property.
I would solve this issue by using a per-object meta class. You can mock the property getter (or setter) by altering the metaClass of the service object. Be aware that meta-class changes are rolled back by Grails in-between execution of test methods:
service.metaClass.mockedProp = {-> ... }

Grails 2.1 Unit Testing Command Object mockForConstraintsTests not working?

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.

Grails Spring Security Testing

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.

Grails unit testing help needed

I want to test a Grails controller which calls a service. I'd like to mock the service. The Service has a method:
JobIF JobServiceIF.getJob(int)
and JobIF has a method:
String JobIF.getTitle()
Here's my controller
def workActivities = {
JobIF job = jobService.getJob(params.id)
[career:job]
}
I understand that I need to mock the service and the job class (there are concrete implementations for both) but I'm struggling to get my head around the Groovy mocking object syntax. How do I mock a job and set the title to something, say "Architect" and then test the code?
So far I have:
void testWorkActivities() {
def controller = new CareersController()
... // Mocking stuff I don't know how to do
controller.params.id = 12
def model = controller.workActivities()
assertEquals "Architect", model["career"].getTitle()
}
You basically have two choices
Use the Groovy mocking classes, i.e. MockFor and StubFor
Use the Grails mock classes by calling the mockFor method of GrailsUnitTestCase. The class returned by this method is an instance of GrailsMock
Personally, I have found the Groovy mock objects to a bit more reliable than the Grails mocks. On occasions, I've found that my Grails mock objects were bypassed, even though I appeared to be setting everything up correctly.
Here's an example of how to use the Groovy mocks:
void testCreateSuccess() {
def controller = new CareersController()
// Create a mock for the JobService implementation class
def mockJobServiceFactory = new MockFor(JobService)
mockJobServiceFactory.demand.getJob {def id ->
// Return the instance of JobIF that is used when the mock is invoked
return new Job(title: "architect")
}
// Set the controller to use the mock service
controller.jobService = mockJobServiceFactory.proxyInstance()
// Do the test
controller.params.id = 12
def model = controller.workActivities()
assertEquals "Architect", model["career"].getTitle()
}
The process is basically the same when using the Grails mocks, but you call the mockFor method of the test class, instead of instantiating MockFor.