I am trying to make sure a user
can vote
a given project
only once (no duplicate voting allowed). After some search, looks like there is a composite unique constraint to achieve this. However, I am having some issue in the integration testing. My domain classes are as follows.
package grailstuts
class User {
String name
static hasMany = [ projects: Project, votes: Vote ]
static constraints = { name(nullable: true) }
static mapping = { projects cascade: "all-delete-orphan" }
}
.
package grailstuts
class Project {
String title
Set votes = []
static belongsTo = [ user: User ]
static hasMany = [ votes: Vote ]
static constraints = { title(nullable: true) }
}
.
package grailstuts
class Vote {
static belongsTo = [ user: User, project: Project ]
static constraints = { user(unique: 'project') }
}
Please note the unique
constraint in the Vote
class. Then my integration test looks like this:
package grailstuts
import spock.lang.*
class VoteIntegrationSpec extends Specification {
void "Testing uniqueness"() {
given: "A user and a project"
def user = new User();
def project = new Project();
user.addToProjects(project)
user.save(failOnError: true)
when: "The user votes the project"
def vote = new Vote()
user.addToVotes(vote)
project.addToVotes(vote)
then: "The user should not be able to vote the same project again"
def vote2 = new Vote()
user.addToVotes(vote2)
project.addToVotes(vote2)
}
}
This integration test passes without any error. But I was thinking this test should fail, because the user is voting again for the same project (in the then:
block), which should not be possible based on the static constraints = { user(unique: 'project') }
in the Vote
class. Cannot seem to figure this out, can anyone please point out what I am doing wrong?
Thank you for your help.
The reason for this behavior is that the test is not validated.
Since voting is per user and per project (My assumption) as you said you need a composite uniqueness:
package grailstuts
class Vote {
static belongsTo = [ user: User, project: Project ]
static constraints = {
user unique: 'project'
}
}
Your spec would be:
void "Testing uniqueness"() {
given: "A user and a project"
def user = new User()
def project = new Project()
user.addToProjects(project)
user.save(failOnError: true)
when: "The user votes the project"
def vote = new Vote(user:user,project:project).save()
then: "The user should not be able to vote the same project again"
// def vote2 = new Vote(user:user,project:project).save(flush:true,failOnError:true)
// or
new Vote(user:user,project:project).validate() == false
}