Grails Build Test Data Plugin - MissingMethodException when calling DomainObject.build() - grails

The Crux
I am getting the following error in my unit test when calling MyDomainObject.build() via the Build Test Data plugin:
The Exception
groovy.lang.MissingMethodException: No signature of method: us.maponline.pesticide.PesticideProfile.addToApplicators() is applicable for argument types: (us.maponline.pesticide.PesticideApplicator) values: [us.maponline.pesticide.PesticideApplicator : null]
Possible solutions: getApplicators()
at grails.buildtestdata.handler.NullableConstraintHandler.addInstanceToOwningObjectCollection(NullableConstraintHandler.groovy:121)
at grails.buildtestdata.handler.NullableConstraintHandler.populateDomainProperty(NullableConstraintHandler.groovy:88)
at grails.buildtestdata.handler.NullableConstraintHandler.handle(NullableConstraintHandler.groovy:17)
at grails.buildtestdata.DomainInstanceBuilder.createMissingProperty(DomainInstanceBuilder.groovy:187)
at grails.buildtestdata.DomainInstanceBuilder.populateInstance(DomainInstanceBuilder.groovy:147)
at grails.buildtestdata.DomainInstanceBuilder.build(DomainInstanceBuilder.groovy:124)
at grails.buildtestdata.DomainInstanceBuilder.build(DomainInstanceBuilder.groovy:123)
at grails.buildtestdata.BuildTestDataService$_addBuildMethods_closure1.doCall(BuildTestDataService.groovy:25)
at us.maponline.pesticide.PesticideLogServiceTests.testSaveLog(PesticideLogServiceTests.groovy:20)
| Completed 1 unit test, 1 failed in 5289ms
per the stack trace, this is happening within the buildtestdata plugin code. It seems that my class, PesticideApplicator, is null when it is being added to the PesticideProfile class.
How is it possible that the class I'm asking to be built is null when being passed to the PesticideProfile?
Source Code
Test Case
#TestFor(PesticideLogService)
#Build([PesticideLog,PesticideApplicator,PesticideProfile])
class PesticideLogServiceTests
{
void testSaveLog() {
PesticideApplicator applicator = PesticideApplicator.build()
def result = service.createLog(applicator, new Date())
result.errors.each {
log.info "got an error. field = $it.field, message:$it.defaultMessage, rejected value = $it.rejectedValue "
}
assert result: 'no result returned'
assert result.success: 'save failed'
assert result.result instanceof PesticideLog: "result was not PesticideLog"
assert applicator.user.pesticideLogs.size() > 0 : 'expected at least on log to be created.'
}
}
PesticideProfileLog
class PesticideProfile
{
def User user
String companyName
static constraints = {
}
static belongsTo = User
static hasMany = [sites: PesticideSite, applicators: PesticideApplicator]
}
PesticideApplicator
class PesticideApplicator
{
String firstName
String lastName
String company
PesticideApplicatorLicense licenseType
Phone phoneNumber
static belongsTo = [profile:PesticideProfile]
static constraints = {
company blank: false, maxSize: 55
firstName blank: false, maxSize: 55
lastName blank: false, maxSize: 100
phoneNumber nullable: true
}
static mapping = {
licenseType length: 55
}
def getUser(){
profile?.user
}
}
Thanks for all your help!

The issue is caused by the build test data plugin attempting to set the value of the user in the PesticideApplicator. The problem is that getUser() isn't a field, it's just a utility helper:
...
def getUser(){
profile?.user
}
...
Removing getUser() from the PesticideApplicator solved the problem.
That said, I'd still like a helper method to access the user (good to not let my code know about the innards of another class). Marking the method #Transient didn't work; the error still appeared. Short of renaming the method, how can I instruct the build test data plugin to ignore this getter?
Thanks!

Related

Grails 3.3.10 value set in domain method is not being saved

I have a User class with a resetPasswordToken attribute, that is a UUID set when a user tries to reset his password.
On Grails 2.5.6 I had something like this that worked OK:
class UserController {
def forgotPassword(String email)
{
...
def user = User.findByEmail(email)
user.setPasswordToken()
user.save(flush: true()
...
}
}
class User {
...
String resetPasswordToken
static transients = ['passwordToken']
def setPasswordToken()
{
...
this.resetPasswordToken = (java.util.UUID.randomUUID() as String)
}
}
Now I migrated that to GRails 3.3.10 and the resetPasswordToken is NULL on the database after the forgotPassword action is invoked. If I do a println after the user.setPasswordToken() is invoked, I can see the resetPasswordToken is set to an UUID, but is not in the DB. Also checked for errors on the save, and there are no errors.
Strange thing, if I do user.resetPasswordToken = "xxxx" in the controller, the value is saved into the database correctly.
Not sure what is going on with the value set in the setPasswordToken() not being saved into the DB. Any pointers?
See the comment at https://github.com/grails/grails-data-mapping/issues/961#issuecomment-309379214. The issue you are experiencing is one of dirty checking, which changed in GORM 6.1.
Consider this code...
class Person {
String name
String email
void updateName(String newName) {
this.name = newName
}
static constraints = {
email email: true
}
}
That updateName method will not result in the name property being marked as dirty. The following code would result in the name property being marked as dirty:
class Person {
String name
String email
void updateName(String newName) {
setName newName
}
static constraints = {
email email: true
}
}
If you really want to turn on the old way of dirty checking you can do that per the instructions in the comment I linked above but be aware of the performance penalty of doing so. The recommended approach would be to use the setter or to explicitly mark the property as dirty using the markDirty method.
I hope that helps.

Object is not saved in spock integration test

I have a Token entity:
class Token {
/**
* Constants for various namespaces
*/
public static final String NS_PASSWORD_RESET = "pass-reset";
/**
* A simple string unlimited in content that defines a scope of the token
*/
String namespace
/**
* This fields holds an identifier for anything specific that the process might need
*/
Long identifier
/**
* The actual token itself
*/
String token
Timestamp dateCreated
Timestamp lastUpdated
Timestamp expiration
static mapping = {
autoTimestamp true
}
static constraints = {
}
}
and a service class with a following method:
def creareNewToken(String ns, int timeout) {
def token = new Token()
token.setNamespace(ns)
token.setToken(this.generateToken(15))
//persist the object
token.save(flush: true)
return token
}
I created an integration test for the service class:
class TokenServiceIntegrationSpec extends IntegrationSpec {
TokenService tokenService
def "test creareNewToken"() {
when:
def token = tokenService.creareNewToken(Token.NS_PASSWORD_RESET, 60)
then:
token instanceof Token
token.getNamespace() == Token.NS_PASSWORD_RESET
token.getToken().length() == 15
token.getDateCreated() == ''
}
}
When I execute the test, I get:
Failure: test
creareNewToken(com.iibs.security.TokenServiceIntegrationSpec)
| Condition not satisfied:
token.getDateCreated() == ''
| | |
| null false
com.iibs.security.Token : (unsaved)
at com.iibs.security.TokenServiceIntegrationSpec.test creareNewToken(TokenServiceIntegrationSpec.groovy:31)
What could be the reason for this problem? Is seems like the object is actually not saved, and, of coarse, the dateCreated is not populated as well. My question is why it is not saved? I have number of other tests that build in a similar way, and they work without any issue.
Thank you for any advice.
You have two fields (identifier and expiration) which you are not setting. By default every field is not nullable. Try adding:
assert token.save(...)
To check if your object is really being saved.
If you want them to accept null as a value you need to specify it in your constraints
static constraints = {
identifier nullable: true
expiration nullable: true
}
Try adding failOnError:true to the options on save, if only for debugging purposes. The resulting stack trace will usually point out if a field is not set, etc.
def creareNewToken(String ns, int timeout) {
def token = new Token()
token.setNamespace(ns)
token.setToken(this.generateToken(15))
//persist the object
token.save(flush: true, failOnError:true)//this will throw an error if save does not occur
return token
}

one-to-many mapping in grails throwing exception

I am new to Groovy & Grails. I am working on one of the sample one-to-many relationship in Grails.
The below is the code.
class User {
//properties
String login
String password
String role
//constraints and order of display of fields in UI
static constraints = {
login(blank: false, nullable: false, unique: true)
password(blank: false, nullable: false, password: true)
role(inList:["Admin", "Member"])
}
static hasMany = [posts : Post]
}
class Post {
String content
Date dateCreated
static constraints = {
content(blank: true)
}
static belongsTo = [user : User]
}
My Test class in Groovy
#TestFor(User)
class UserTests {
void testUserToPost() {
def user = new User(login: "joe", password: "joe", role:"Admin")
user.addToPosts(new Post(content: "First"));
user.addToPosts(new Post(content: "Second"));
user.addToPosts(new Post(content: "Third"));
user.save(flush: true)
assertEquals 3, User.get(user.id).posts.size()
}
}
While running the test class, getting following exception:
groovy.lang.MissingMethodException: No signature of method: com.library.forum.User.addToPosts() is applicable for argument types: (com.library.forum.Post) values: [com.library.forum.Post : (unsaved)]
Possible solutions: getPosts() at com.library.forum.UserTests.testUserToPost(UserTests.groovy:17)
Can anyone tell me where is the problem in code.
Since Grails 2.1.4, there's a change in mock behavior because of performance issue. So you need to mock all associated entities of the mocked entity.
See GRAILS-9637 - Due to a performance issue, #Mock no longer mocks
associated entities of the mocked entity. These have to be manually
specified. For example the following test will fail in 2.1.4 and
above:
#Mock(Author)
void testAddToBooks() {
def a = new Author()
a.addToBooks(new Book())
}
To correct the above test you need to mock both Author and Book:
#Mock([Author, Book])
void testAddToBooks() {
def a = new Author()
a.addToBooks(new Book())
}
You can check this reference.
You need to mock all related domain classes. Change :
#TestFor(User)
class UserTests {
to
#TestFor(User)
#Mock(Post)
class UserTests {
If you need, the mock annotation support a list of classes, for example: #Mock([Domain1, Domain2, Domain3])

grails: findallbyidinlist method

In my grails project, I've used the method Object.findAllByIdInList(), passing a list as parameter.
The code used is the following:
def allSelectedIds = ReceiptItem.findAllByIdInList(par)
In which the ReceiptItem is a domain class defined as follows:
class Receipt {
double totalAmount;
Date releaseDate;
int vatPercentage;
int discount;
Boolean isPayed;
Boolean isInvoice;
static belongsTo = [patient:Patient]
static hasMany = [receiptItems:ReceiptItem]
static constraints = {
receiptItems(blank: false)
patient(blank: false)
totalAmount(blank: false)
vatPercentage(blank: false, nullable: false)
}
}
and par is the list of ids defined as follows:
def par = params.list("receiptItemsSelected")
receiptItemsSelected is defined in the gsp page into the remoteFunction() as follows:
params: '\'receiptItemsSelected=\' + jQuery(this).val()'
The problem is that the line above throws the following exception:
java.lang.String cannot be cast to java.lang.Long. Stacktrace follows:
Message: java.lang.String cannot be cast to java.lang.Long
I don't understand why it is throwing this exception.
Thanks for your help
Probably list par has ids as String. Generally id for domain objects is stored as Long. Try this instead
ReceiptItem.findAllByIdInList(par*.toLong())
*Also make sure that id represented as string isNumber().
assert !'C'.isNumber()
assert '4'.isNumber()

Grails domain class unit test errors

I wrote the following domain class with its unit test. When I run the tests, I get the error message
No such property: admittedMobileUser. When I comment that line in domain class I get the same problem on other fields. Does anyone knows how to solve it?
class MobileUser {
String userName
String userDevice="Android"
Integer userCluster
Boolean admittedMobileUser
Date lastTimeUpdatedUserSpaceTime=new Date()
byte[] userSpaceTimeXml
static constraints = {
userName blank:false, unique:true
userDevice blank:false
userCluster validator : {val-> return val > 0}
admittedMobileUser
lastTimeUpdatedUserSpaceTime
userSpaceTimeXml maxSize:1024*1024
}
String toString(){
return "${userName}_${userCluster}"
}
}
remove such rows from constraints :
....
admittedMobileUser
lastTimeUpdatedUserSpaceTime
....
or add minimum one constraint to each!

Resources