Grails spock test fails with "GroovyCastException: Cannot cast object" - validation

I have a simple class that I'm writing a test for. Something weird happens when I call validate() on an instance of that class, which relates to my custom validator for my date property. If my custom validator calls a static method, everything seems to work fine. However, if I call a non-static method (which I need to as I need to check some other properties of my instance) I get the following error:
Condition failed with Exception:
testDate.validate(['date']) == valid
| |
| org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class hegardt.backend.grails.model.person.TestDate' with class 'java.lang.Class' to class 'hegardt.backend.grails.model.person.TestDate'
| at hegardt.backend.grails.model.person.TestDate._clinit__closure1$_closure2(TestDate.groovy:20)
| at groovy.lang.Closure.call(Closure.java:405)
| at org.grails.datastore.gorm.validation.constraints.ValidatorConstraint.processValidate(ValidatorConstraint.java:100)
| at org.grails.datastore.gorm.validation.constraints.AbstractConstraint.validate(AbstractConstraint.java:88)
| at grails.gorm.validation.DefaultConstrainedProperty.validate(DefaultConstrainedProperty.groovy:601)
| at grails.validation.Validateable$Trait$Helper.doValidate(Validateable.groovy:192)
| at grails.validation.Validateable$Trait$Helper.validate(Validateable.groovy:163)
| at grails.validation.Validateable$Trait$Helper.validate(Validateable.groovy:129)
| at hegardt.backend.grails.model.person.TestDateSpec.test(TestDateSpec.groovy:15)
<hegardt.backend.grails.model.person.TestDate#48bb8764 date=null privateVar=false grails_validation_Validateable__beforeValidateHelper=org.grails.datastore.gorm.support.BeforeValidateHelper#1624fd07 grails_validation_Validateable__errors=grails.validation.ValidationErrors: 0 errors>
Here's my class definition:
#GrailsCompileStatic
class TestDate implements Validateable {
LocalDate date
boolean privateVar
static constraints = {
date nullable: true, validator: {LocalDate val -> validateDate(val)}
}
private validateDate(LocalDate val) { // If this method is static, everything works fine
return privateVar
}
}
and here's my test class
class TestDateSpec extends Specification {
#Unroll
void "test"() {
given:
TestDate testDate = new TestDate(date: date)
expect:
testDate.validate(['date']) == valid // This call fails for all 4 test cases...
where:
date | valid
null | true
LocalDate.now().plusDays(1) | false
LocalDate.now() | false
LocalDate.now() | true
}
}
PS
I have also tried without #GrailsCompileStatic but this just generates a different "cast" related error:
Condition failed with Exception:
testDate.validate(['date']) == valid
| |
| java.lang.IllegalArgumentException: object is not an instance of declaring class
| at org.grails.datastore.gorm.validation.constraints.builder.ConstrainedPropertyBuilder.doInvokeMethod(ConstrainedPropertyBuilder.java:65)
| at groovy.util.BuilderSupport.invokeMethod(BuilderSupport.java:64)
| at groovy.lang.GroovyObjectSupport.invokeMethod(GroovyObjectSupport.java:44)
| at hegardt.backend.grails.model.person.TestDate._clinit__closure1$_closure2(TestDate.groovy:19)
| at groovy.lang.Closure.call(Closure.java:405)
| at org.grails.datastore.gorm.validation.constraints.ValidatorConstraint.processValidate(ValidatorConstraint.java:100)
| at org.grails.datastore.gorm.validation.constraints.AbstractConstraint.validate(AbstractConstraint.java:88)
| at grails.gorm.validation.DefaultConstrainedProperty.validate(DefaultConstrainedProperty.groovy:601)
| at grails.validation.Validateable$Trait$Helper.doValidate(Validateable.groovy:192)
| at grails.validation.Validateable$Trait$Helper.validate(Validateable.groovy:163)
| at grails.validation.Validateable$Trait$Helper.validate(Validateable.groovy:129)
| at hegardt.backend.grails.model.person.TestDateSpec.test(TestDateSpec.groovy:15)
<hegardt.backend.grails.model.person.TestDate#1e742012 date=null privateVar=false grails_validation_Validateable__beforeValidateHelper=org.grails.datastore.gorm.support.BeforeValidateHelper#4f3967c7 grails_validation_Validateable__errors=grails.validation.ValidationErrors: 0 errors>

You are attempting to invoke an instance method (validateDate) from a static context (static constraints block) which is not allowed. You could mark validateDate as static but that moves the problem to privateVar which is an instance variable so you would not be able to reach that from a static method. It isn't clear what role that field plays so it isn't clear how best to deal with that, but the problem described in the question is caused because you are attempting to invoke an instance method from a static context.

Related

#Cacheable in java 17

I have an application with spring 2.6.8, I have migrated it to 2.7.4.
And everything works correctly.
But when I have upgraded from java 11 to java 17 it gives me the following error
#Cacheable(value = "datoAuxiliar", key = "{#nombre, #tipo}", unless = "#result == null")
public DatoAuxiliar findByTipoAndSecurityDomainAndNombre(TipoDatoAuxiliar tipo, SecurityDomain securityDomain,
String nombre);
-- ERROR
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tipoContratoSelectItemController': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Null key returned for cache operation (maybe you are using named params on classes without debug info?) Builder[public abstract java.util.List com.xxx.xxx.repository.DatoAuxiliarRrhhRepository.findByTipoAndSecurityDomainAndDeletedIsNull(com.abalia.elser.domain.enumeration.TipoDatoAuxiliar,com.abalia.elser.domain.SecurityDomain)] caches=[datoAuxiliar] | key='#tipo' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='#result == null' | sync='false'
I've tried several things but they don't work for me.
Can someone help me with this problem?
Thanks.

SpecFlow Step Generation for Scenario Outline Generating Incorrect Methods

I'm new in Visual Studio. I'm using Visual Studio 2015 with SpecFlow. Below is the Feature File:
#mytag
Scenario Outline: Successful Authentication
Given I am a user of type <user>
When I hit the application URL
And I provide <email>
And I click on Log In Button
Then I will be landed to the Home Page
And I will be able to see <name> on the Home Page
Examples:
| user | email | name |
| admin | a.b#example.com | alpha |
| non-admin | b.c#example.com | beta |
When I generate the step definitions I'm expecting parameters in place of the variables, instead the method is generated as below:
[Given(#"I am a user of type admin")]
public void GivenIAmAUserOfTypeAdmin()
{
ScenarioContext.Current.Pending();
}
I was instead expecting a method like:
[Given(#"I am a user of type '(.*)'")]
public void GivenIAmAUserOfType(string p0)
{
ScenarioContext.Current.Pending();
}
What am I missing?
As an example, surrounding the <user> in the Given step with '' like this,
Given I am a user of type '<user>'
will generate the desired results. It's probably needed in order to recognize the regular expression.

Fitnesse reads fixture class as method, gives 'missing method' exception

I have developed a maven project using DoFixture.
My JAVA code looks somewhat like this:
Package A
Class P extends DoFixture
Method X
Package A
Class Q extends DoFixture
Method X
Method Y
When I make a Fitnesse table for this, like,
! |A.Q|
| X |
| Y |
On running it, Fitnesse returns this exception-> method missing : AdotQ in class A.Q, but when I run,
! |A.P|
| X |
it runs fine.
Not able to understand why Fitnesse is reading AdotQ as a method when it is a class in my code.Please note, I have compiled the code using mvn install.

Integration tests for Rest API

I'd like to get different pointe of views about how to create integration tests for Rest APIs.
The first option would be using cucumber as described in the "The Cucumber Book":
Scenario: Get person
Given The system knows about the following person:
| fname | lname | address | zipcode |
| Luca | Brow | 1, Test | 098716 |
When the client requests GET /person/(\d+)
Then the response should be JSON:
"""
{
"fname": "Luca",
"lname": "Brow",
"address": {
"first": "1, Test",
"zipcode": "098716"
}
}
"""
The second option would be (again) using cucumber, but removing the technical detail as described here:
Scenario: Get person
Given The system knows about the following person:
| fname | lname | address | zipcode |
| Luca | Brow | 1, Test | 098716 |
When the client requests the person
Then the response contains the following attributes:
| fname | Luca |
| lname | Brow |
| address :first | 1, Test |
| address :zipcode | 098716 |
And the third option would be using Spring as described here:
private MockMvc mockMvc;
#Test
public void findAll() throws Exception {
mockMvc.perform(get("/person/1"))
.andExpect(status().isOk())
.andExpect(content().mimeType(IntegrationTestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.fname", is("Luca")))
.andExpect(jsonPath("$.lname", is("Brow")))
.andExpect(jsonPath("$.address.first", is("1, Test")))
.andExpect(jsonPath("$.address.zipcode", is("098716")));
}
I really like the second option since it looks cleaner to business users and testers, but on the other hand for a developer that will consume this API the first option looks more visible since it shows the JSON response.
The third option is the easiest one since it's just Java code, but the readability and the cross-team interaction is not as nice as cucumber.
You should use the third option but not with junit, you should do it using spock.This is the best of both the worlds.
Spock tests are written like this
def "description of what you want to test"() {
given:
//Do what is pre-requisite to the test
when:
def response = mockMvc.perform(get("/person/id")).andReturn().getResponse();
then:
checkForResponse.each {
c->c(response )
}
where:
id | checkResponse
1 | [ResponseChecker.correctPersondetails()]
100 | [ResponseChecker.incorrectPersondetails()]
}
Integration test are made to test if components of your application can work together. For example, you test some requests to database and mvc controller with integration tests. Integration tests are here to test your infrastructure.
On the other hand, BDD tests are made to facilitate communication between development and specifications. The common idea is to write tests or specification by example. There are definitely not design to write integration tests.
I would recommend the third option.

grails ajax call row-was-updated-or-deleted-by-another-transaction-or-unsaved-value-mapping-was

I am using Grails 2.3.5 and I have a controller which contains a ajaxDelete method. This method receives the name as a String of the entity i want to delete. I am using a service to delete the entity which I call from within my controller.
The first time the services deleteSvnUser method is called the SVN user is deleted and my div on the page is updated with a alert stating that the user has been deleted. The second time I delete a user i get the following error:
row-was-updated-or-deleted-by-another-transaction-or-unsaved-value-mapping-was...
I have tried a couple of things to get round this:
Adding the #transactional annotation to my service (which I shouldn't have to because it should be transactional by default).
flushing my deletes (flush:true)
Refreshing the entity before i delete it (.refresh)
Locking the entity when I retrieve it (entity.lock(id))
None of the above have worked. I'm not sure what else to do to get around this.
Can anyone help? my code is below:
Controller
class SvnUserController {
def svnUserService
def ajaxDelete() {
if (!params.selectedSvnUser) {
request.error = "The selected Svn User does not exist"
render(template:"svnUserList", model:[svnUserInstanceList: SvnUser.list(params).sort{it.name}, svnUserInstanceTotal: SvnUser.count()])
return
}
String outcome = svnUserService.deleteSvnUser(params.selectedSvnUser)
switch (outcome){
case "":
request.message = "Svn User ${params.selectedSvnUser} deleted"
break
default: request.error = outcome
}
}
def svnUsers = svnUserService.getAllSvnUsers(params)
render(template:"svnUserList", model:[svnUserInstanceList: svnUsers, svnUserInstanceTotal: svnUsers.size()])
return
}
}
Service
class SvnUserService {
public String deleteSvnUser(String userName) {
String outcome = ""
try {
SvnUser svnUserInstance = SvnUser.findByName(userName)
def groups = SvnGroupController.findAllBySvnUserName(userName)
groups.each { SvnGroup group ->
group.removeFromSvnUsers(svnUserInstance)
group.save()
}
def userPermissionsList = UserPermission.findAllBySvnUser(svnUserInstance)
userPermissionsList.each {
def repoDirectory = it.repositoryDirectory
repoDirectory.removeFromUserPermissions(it)
it.delete()
}
svnUserInstance.merge()
svnUserInstance.delete()
}
catch (DataIntegrityViolationException e) {
outcome = "A error occurred while attempting to delete the Svn User from file."
}
return outcome
}
}
The stacktrace is as follows:
Error |
2014-06-10 15:10:07,394 [http-bio-8080-exec-6] ERROR errors.GrailsExceptionResolver - StaleObjectStateException occurred when processing request: [POST] /subzero/svnUser/ajaxDelete - parameters:
selectedSvnUser: ruby2
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.uk.nmi.subzero.SvnGroup#2]. Stacktrace follows:
Message: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.uk.nmi.subzero.SvnGroup#2]
Line | Method
->> 72 | deleteSvnUser in com.uk.nmi.subzero.SvnUserService
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 87 | ajaxDelete in com.uk.nmi.subzero.SvnUserController
| 200 | doFilter . . in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter in grails.plugin.cache.web.filter.AbstractFilter
| 1145 | runWorker . . in java.util.concurrent.ThreadPoolExecutor
| 615 | run in java.util.concurrent.ThreadPoolExecutor$Worker
^ 744 | run . . . . . in java.lang.Thread
I can't see any problem with your code. Grails should handle the transaction fine.
If your object mapping is set up correctly, the svnUserInstance.delete() call should delete the child objects too, so I don't think you even need the lines between svnUserInstance = SvnUser.findByName(userName) and the delete.
How are you calling the ajaxDelete? Is there any chance it is being called incorrectly the second time?

Resources