grails domain class not mocked - unit-testing

I'm trying to mock the Role class generated by shiro plugin in a Grails 2.2.1 app. When i'm runnint the unit test I'm getting this error that looks like the dynamics method are not added.
This is the Role class:
class Role {
String name
static hasMany = [ users: User, permissions: String ]
static belongsTo = User
static constraints = {
name nullable: false, blank: false, unique: true
}
}
and this is the unit test:
#TestFor(UserService)
#TestMixin(DomainClassUnitTestMixin)
#Mock([User, Role])
class UserServiceTests {
void testSaveFacebookUser(){
//given
def adminRole = new Role(name: RoleEnum.ADMIN.name)
adminRole.addToPermissions("*:*")
adminRole.save()
}
}
The stacktrace:
Running 1 unit test... 1 of 1
Failure: testSaveFacebookUser(a4o.services.UserServiceTests)
groovy.lang.MissingMethodException: No signature of method: a4o.Role.addToPermissions() is applicable
for argument types: (java.lang.String) values: [*:*]
UPDATE
found this on JIRA, but it says it was closed for 2.0.4 http://jira.grails.org/browse/GRAILS-8779 . Maybe it's open again.

AFAIK, the hasMany statement is supposed to be used to connect the given class with other Grails domain classes, not with other object. If you need to save a list of permissions as String objects, you need to create (and handle!) that list of strings outside the hasMany block; something like this:
class Role {
String name
List<String> permissions
static hasMany = [ users: User ]
static belongsTo = User
static constraints = {
name nullable: false, blank: false, unique: true
}
}
Anyways, my suggestion is not to reinvent the wheel and use the sprint security plugin (or another one of your choice).

upgrading to grails 2.2.2 solved this issue

Related

Spock unit test using spring data causing errors in Optional

I'm starting to perform tests using the Spock Framework in a Spring Boot + Spring Data project.
The problem occurs when I try to Mock my repository, but specifically in some method that the return is Optional.
Cannot invoke method orElse() on null object
java.lang.NullPointerException: Cannot invoke method orElse() on null object
at br.com.moskit.jivochat.service.UserService.getResponsible(UserService.groovy:37)
at br.com.moskit.jivochat.service.UserServiceTest.Retrive the responsible of interaction in JivoChat by configs of plugin item(UserServiceTest.groovy:65)
My implemetation of test:
class UserServiceTest extends Specification {
UserService userService
void setup() {
userService = new UserService()
userService.userRepository = Mock(UserRepository)
GroovyMock(Optional)
}
def "Retrive the responsible of interaction in JivoChat by configs of plugin item"() {
given: 'that exist a collection of JivoChat interaction configurations'
List<Map> agents = null
Map configs = [responsibleId: 1]
userService.userRepository.findById(_) >> Optional.of(new User(username: "XPTO")).orElse("null")
when: 'the main method is called'
User user = userService.getResponsible(configs, agents)
then: 'the method get last agent and search in DB by e-mail'
1 * userService.userRepository.findById(_)
}
}
My method:
User getResponsible(Map configs, List<Map> agents) {
//Ommited...
Integer responsibleId = configs.responsibleId as Integer
Optional<User> userOptional = userRepository.findById(responsibleId)
User user = userOptional.orElse(null)
user
}
This is a classic one and the answer can be found in Spock manual chapter "Combining Mocking and Stubbing":
NOTE: Mocking and stubbing of the same method call has to happen in the same interaction.
So the solution looks like this:
package de.scrum_master.stackoverflow.q66208875
class User {
int id
String username
}
package de.scrum_master.stackoverflow.q66208875
class UserRepository {
Optional<User> findById(int id) {
Optional.of(new User(id: id, username: "User #$id"))
}
}
package de.scrum_master.stackoverflow.q66208875
class UserService {
UserRepository userRepository = new UserRepository()
User getResponsible(Map configs, List<Map> agents) {
Integer responsibleId = configs.responsibleId as Integer
Optional<User> userOptional = userRepository.findById(responsibleId)
User user = userOptional.orElse(null)
user
}
}
package de.scrum_master.stackoverflow.q66208875
import spock.lang.Specification
class UserServiceTest extends Specification {
UserService userService
void setup() {
userService = new UserService()
userService.userRepository = Mock(UserRepository)
}
def "retrieve the responsible of interaction in JivoChat by configs of plugin item"() {
given: 'that exist a collection of JivoChat interaction configurations'
List<Map> agents = null
Map configs = [responsibleId: 1]
when: 'the main method is called'
User user = userService.getResponsible(configs, agents)
then: 'the method get last agent and search in DB by e-mail'
1 * userService.userRepository.findById(_) >> Optional.of(new User(username: "XPTO"))//.orElse("null")
}
}
See how I combined stubbing the method result and verifying the mock interaction in one line?
You also do not need any GroovyMock(Optional), whatever that was meant for. You also want to make sure to get the findById(_) result type right and remove the false .orElse("null").

Grails unit tests not recognizing .save() on a domain class

I am trying to be a good little programmer and set up Unit tests for my Grails 2.2.3 app. The unit tests that use GORM's injected .save() method are apparently not persisting to the mock test DB. For an example, here is what one test consists of:
#TestFor(TermService)
#Mock(Term)
class TermServiceTests {
void testTermCount() {
def t = new Term(code: "201310").save(validate: false, flush: true, failOnError: true)
println "Printing Term: " + t.toString()
assert 1 == Term.count() // FAILS
assert service.isMainTerm(t) // FAILS
}
}
I did a println that ends up printing Printing Term: null, meaning the Term did not save and return a Term instance. The first assertion is false with Term.count() returning 0.
Does anyone know why this might be? I have a mock Term and TermService (via the TestFor annotation, I believe), so I'm not quite sure why this wouldn't work. Thanks!
Edit: Here is my Term class.
class Term {
Integer id
String code
String description
Date startDate
Date endDate
static mapping = {
// Legacy database mapping
}
static constraints = {
id blank: false
code maxSize: 6
description maxSize: 30
startDate()
endDate()
}
}
Looks like id generator is assigned since you have mentioned about using legacy database. Plus id is not bindable by default in domain class (map construct won't work for id). So, I think you have to end up using like below:
def t = new Term(code: "201310")
t.id = 1
t.save(...)

Using grails configuration values in domain object constraints

Grails 2.2.0
How do I access the custom configuration variables in a Grails domain object constraints.
I would like to have something like this:
class User {
def grailsApplication
String name
static constraints = {
name size: grailsApplication.config.maxlength
}
}
But it fails with "No such property: grailsApplication". I have tried to get it work by following suggestions in getting grails 2.0.0M1 config info in domain object, and static scope? but have not managed to get any combination to work.
How do I access config in domain object constraints? In addition how do I handle such a case in a unit test for the domain constraints?
You can use the grails.util.Holders class to get access to the configuration object as follows:
In Config.groovy:
myMaxSize = 10
In your domain class:
class User {
String name
static constraints = {
name minSize: Holders.config.myMaxSize
}
}

Mocking the "save" method on domain classes

I'm having hard time mocking the save instance method in my unit tests in Grails 1.3.3. I've created a simple domain class named Person, it has one property (nullable) called "name".
package tutorial
class Person {
String name
static constraints = {
name nullable: true
}
}
In my test I'm trying to do something I've found in the documentation:
class PersonTests extends GrailsUnitTestCase {
public void testCanSavePerson() {
def testInstances = []
mockDomain(Person, testInstances)
assertEquals(0, Person.count())
new Person(name: "Bob").save()
assertEquals(1, Person.count())
}
}
However as soon as I run the test what I get is an exception:
java.lang.NullPointerException
at grails.test.MockUtils$_addValidateMethod_closure83.doCall(MockUtils.groovy:973)
at grails.test.MockUtils$_addValidateMethod_closure84.doCall(MockUtils.groovy:1014)
at grails.test.MockUtils$_addDynamicInstanceMethods_closure67.doCall(MockUtils.groovy:736)
at grails.test.MockUtils$_addDynamicInstanceMethods_closure67.doCall(MockUtils.groovy)
at tutorial.PersonTests.testCanSavePerson(PersonTests.groovy:25)
whereas the line 25 is exactly the one that calls save() on newly created instance.
Does anyone knows what am I doing wrong?
This is an already known bug in Grails 1.3.3. Read more about it and find a workaround in the associated JIRA ticket GRAILS-6482.

Testing custom constraints in Grails App

I have the following as my unit test:
void testCreateDealer() {
mockForConstraintsTests(Dealer)
def _dealer= new Dealer( dealerName:"ABC",
Email:"abc-motors#global.com",
HeadOffice:"",
isBranch:false)
assertFalse _dealer.validate()
}
But when I run the test I get the following error:
No signature of method: static com.myCompany.Dealer.findByDealerNameIlike() is applicable for argument types: (java.lang.String) values: [ABC]
I use some custom constraints in my domain class. How Can I test this?
static constraints = {
dealerName(blank:false, validator:
{ val, obj ->
def similarDealer = Dealer.findByDealerNameIlike(val)
return !similarDealer || (obj.id == similarDealer.id)
}
)
Try changing mockForConstraintsTests() to mockDomain() - you're using a Dealer.findX() method in the constraint, which relies on the Dealer domain.
Incidentally, the test will still fail unless you've created a similar dealer in the setUp() method of the test class.
In unit tests, even with mockDomain, the id attribute of domain objects is not set automatically, or auto-incremented. All of the domain objects you create will have an id of null unless you explicitly set it.
Your test is probably failing because the test obj.id == similarDealer.id is true, since they both have id: null. Try setting the id attribute of your mocked dealer objects.