I am trying to perform basic unit test on a Grails domain class.
Here is the domain class:
class User {
String username
String password
String email
static constraints = {
username size: 4..15, blank: false, unique: true
password size: 5..15, password: true, blank: false
email email: true, blank: false
}
}
Here is the unit test class:
#TestFor(User)
class UserTests {
void testCreateUser() {
def u = new User(username:"ab")
assertFalse "There should be errors", u.validate()
assertTrue "Should be errors here", u.hasErrors()
}
}
username is constrained by size from 4 to 15. However, when I run grails test-app the above test succeeds. I don't understand why the constraint isn't causing it to fail.
You didn't write which Grails version you use, but generally you should set up User class to be tested for constraint checks. Add this to your UserTests
def setUp() {
mockForConstraintsTests(User)
}
Related
I have a validator inside a domain class and I have a problem testing the controller for Lagerort.
com.example.xyz.LagerortControllerSpec > Test the update action performs an update on a valid domain instance FAILED
java.lang.IllegalStateException: Either class [com.example.xyz.Lagertyp] is not a domain class or GORM has not been initialized correctly or has already been shutdown. Ensure GORM is loaded and configured correctly before calling any methods on a GORM entity.
If I omit the validator, everything tests fine, but that's not what I want.
The domain class:
class Lagerort {
String lagerort
Lagertyp lagertyp
String beschreibung
static auditable = true
static constraints = {
lagerort(nullable: false, blank: false, unique: true)
lagertyp(nullable: false, blank: false, validator: { val, obj ->
// Only ONE Lagerort may be "Schrott"
if (Lagertyp.count() > 0) {
def _LAGERTYPSTRING="Schrott"
Lagertyp lagertypschrott = Lagertyp.findByLagertyp(_LAGERTYPSTRING)
if (obj.lagertyp == lagertypschrott && Lagerort.countByLagertyp(lagertypschrott)>0) return ['lagerortschrottunique',_LAGERTYPSTRING]
}
})
beschreibung(nullable: false, blank: false)
}
String toString(){lagerort}
}
The testCompile part of the dependencies in build.gradle looks like this:
testCompile "org.grails:grails-plugin-testing"
testCompile "org.grails.plugins:geb"
testCompile "org.grails.plugins:hibernate5"
testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
testRuntime "net.sourceforge.htmlunit:htmlunit:2.18"
I've already tried creating a few objects of type Lagertyp in the setup part of the controller tests so that Lagertyp.count() > 0 would be true for the validator, but that didn't help either.
The populateValidParams of the LagerortControllerSpec / test looks like this:
def populateValidParams(params) {
assert params != null
params["lagerort"] = 'Fa.Conrad'
params["lagertyp"] = ["lagertyp": 'Fa.Conrad', "beschreibung": 'Motor befindet sich bei Fa.Conrad']
params["beschreibung"] = 'in Reparatur bei Fa. Conrad'
}
The LagerortController: https://pastebin.com/PpZ5zqMm
The test for LagerortController: https://pastebin.com/pxZ6UeVK
Any ideas?
Found the solution, I had to also mock Lagertyp, like so:
#Mock([Lagerort,Lagertyp])
It seems that I have to include all domain classes which are part of the tests inside the #Mock list, even those that are referenced indirectly.
I have the following Domain class with derived property lowercaseTag.
class Hashtag {
String tag
String lowercaseTag
static mapping = {
lowercaseTag formula: 'lower(tag)'
}
}
If I run the following unit test, it will fail on the last line, because lowercaseTag property is null and by default all properties have nullable: false constraint.
#TestFor(Hashtag)
class HashtagSpec extends Specification {
void "Test that hashtag can not be null"() {
when: 'the hashtag is null'
def p = new Hashtag(tag: null)
then: 'validation should fail'
!p.validate()
when: 'the hashtag is not null'
p = new Hashtag(tag: 'notNullHashtag')
then: 'validation should pass'
p.validate()
}
}
The question is how to properly write unit tests in such cases? Thanks!
As I'm sure you've figured out, the lowercaseTag cannot be tested because it's database dependent; Grails unit tests do not use a database, so the formula/expression is not evaluated.
I think the best option is to modify the constraints so that lowercaseTag is nullable.
class Hashtag {
String tag
String lowercaseTag
static mapping = {
lowercaseTag formula: 'lower(tag)'
}
static constraints = {
lowercaseTag nullable: true
}
}
Otherwise, you'll have to modify the test to force lowercaseTag to contain some value so that validate() works.
p = new Hashtag(tag: 'notNullHashtag', lowercaseTag: 'foo')
I am using Spring security in my grails project. I have installed the spring-security-core plugin and spring-security-ui plugin.
The domain classes I have used for Person and Authority are User and Role respectively
As per project requirements, I have modified my User.groovy class and the code for the same is as below:
class User {
transient springSecurityService
//Mandatory Fields
String employeeId
String firstName
String lastName
String password
String emailId
//Other Fields
String mobileNumber
String address
String city
String zipCode
User manager
static hasMany = [previousPasswords: String]
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static transients = ['springSecurityService']
static constraints = {
employeeId blank: false, unique: true
firstName blank: false
lastName blank: false
password blank: false, password: true, validator: { val, obj ->
if(obj.previousPasswords) {
return !obj.previousPasswords.contains(encode(val.toUpperCase()))
}
return true
}
emailId blank: false, email: true
mobileNumber nullable: true
address nullable: true
city nullable: true
zipCode nullable: true
manager nullable: true
previousPasswords display: false, editable: false
}
static mapping = {
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
previousPasswords = [encode(password.toUpperCase())]
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
previousPasswords << encode(password.toUpperCase())
encodePassword()
}
}
protected String encode(String pwd) {
return springSecurityService.encodePassword(pwd)
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
I am trying to write Unit tests to check the constraints for this unit class
One of my test looks as below
void "test if employeeId can be blank or non-unique"() {
given:
def springSecurityService = mockFor(SpringSecurityService,true)
springSecurityService.encodePassword(){String pwd -> return null}
// def springSecurityServiceFactory = mockFor(SpringSecurityService,true)
// def mockSpringSecurityService = Mock(SpringSecurityService)
// mockSpringSecurityService.metaClass.encodePassword = {String password -> return null}
// User.metaClass.encodePassword = { return null }
// User.metaClass.encode = {password -> return null }
// User.metaClass.getSpringSecurityService = { mockSpringSecurityService }
when: 'employeeId is blank'
def user = new User(employeeId: " ")
user.springSecurityService= springSecurityService
then: 'validation fails'
!user.validate()
user.errors.getFieldError("employeeId").codes.contains("nullable")
when: 'employeeId is unique'
user = new User(employeeId: "empId1", firstName: "f_name", lastName: "l_name", password: "password", emailId: "test#hptest.com")
user.springSecurityService= springSecurityService
then: 'validation succeeds'
user.validate()
user.save(flush: true, failOnError: true)
mockForConstraintsTests(User, [user])
when: 'employeeId is non unique'
def user_2 = new User(employeeId: "empId1")
user_2.springSecurityService= springSecurityService
then: 'validation fails'
!user_2.validate()
user_2.errors.getFieldError("employeeId").codes.contains("unique")
}
I have been trying different ways to mock springSecurityService but all seem to fail. Can anyone suggest a way to mock this service.
Currently I am getting this error.
groovy.lang.MissingMethodException: No signature of method: grails.test.GrailsMock.encodePassword() is applicable for argument types: (com.hp.bots.UserSpec$_$spock_feature_0_0_closure1) values: [com.hp.bots.UserSpec$_$spock_feature_0_0_closure1#18324cd]
at com.hp.bots.UserSpec.test if employeeId can be blank or non-unique(UserSpec.groovy:25)
This test also fails if I try to run it as an integration test (without mocking). I am not able to understand where I am going wrong.
I guess if you replace
springSecurityService.encodePassword(){String pwd -> return null}
with
springSecurityService.demand.encodePassword(){String pwd -> return null}
and
user.springSecurityService= springSecurityService.createMock() (grails 2.3.7)
and for user_2
you should be able to get this test running.
you could have a look here for further documentation. http://grails.org/doc/2.3.7/guide/testing.html
I usually mock services by creating a map with the function(s) that will be called. I would only recommend this approach when only one or two simple functions are being called on the service in question, and these calls do not need to be verified/tracked. In your case your given clause might look like this:
def springSecurityService = [encodePassword: { password ->
return password
}]
I have a command object for registering user, and I want to check how old is the user. This command object has a service dependency. How can I test custom validator for my dateOfBirth property? As it looks now is taken straight from documentation, here.
class RegisterUserCommand {
def someService
String username
String password
String password2
String email
Date dateOfBirth
static constraints = {
// other constraints
dateOfBirth blank: false, validator: {val, obj ->
return obj.someService.calculateAge(val) >= 18
}
}
So basically the question is: how can I mock 'obj' parameter of the validator closure?
The easiest way to test validation on a command object is to use GrailsUnitTestCase.mockForConstraintsTests. A mock validate method will be applied to your command object, and you can just call validate() like you would outside of a test.
Here's an example of how you could write your unit test. The blank constraint isn't meaningful for dates, so I've changed it to nullable: false.
import grails.test.GrailsUnitTestCase
class RegisterUserCommandTests extends GrailsUnitTestCase {
RegisterUserCommand cmd
protected void setUp() {
super.setUp()
cmd = new RegisterUserCommand()
mockForConstraintsTests RegisterUserCommand, [cmd]
}
void testConstraintsNull() {
cmd.dateOfBirth = null
cmd.someService = [calculateAge: { dob -> 18 }]
def result = cmd.validate()
assert result == false
assert cmd.errors.getFieldErrors('dateOfBirth').code == ['nullable']
}
void testConstraintsCustom() {
cmd.dateOfBirth = new Date()
cmd.someService = [calculateAge: { dob -> 17 }]
def result = cmd.validate()
assert result == false
assert cmd.errors.getFieldErrors('dateOfBirth').code == ['validator.invalid']
}
}
Note that your service won't get injected in a unit test (it will in an integration test though), so you'll either need to mock it, as above, or create an instance and assign it to cmd.someservice.
I have a controller that uses a command object in a controller action. When mocking this command object in a grails' controller unit test, the hasErrors() method always returns false, even when I am purposefully violating its constraints. The more baffling thing is that in production, hasErrors() works! So this is just a testing problem.
def save = { RegistrationForm form ->
if(form.hasErrors()) {
// code block never gets executed
} else {
// code block always gets executed
}
}
In the test itself, I do this:
mockCommandObject(RegistrationForm)
def form = new RegistrationForm(emailAddress: "ken.bad#gmail",
password: "secret", confirmPassword: "wrong")
controller.save(form)
I am purposefully giving it a bad email address, and I am making sure the password and the confirmPassword properties are different. In this case, hasErrors() should return true... but it doesn't. I don't know how my testing can be any where reliable if such a basic thing does not work :/
Here is the RegistrationForm class, so you can see the constraints I am using:
class RegistrationForm {
def springSecurityService
String emailAddress
String password
String confirmPassword
String getEncryptedPassword() {
springSecurityService.encodePassword(password)
}
static constraints = {
emailAddress(blank: false, email: true)
password(blank: false, minSize:4, maxSize: 10)
confirmPassword(blank: false, validator: { confirmPassword, form ->
confirmPassword == form.password
})
}
}
Have you tried mockForConstraintsTests ?
E.g. something like...
void testSomething() {
mockForConstraintsTests(RegistrationForm)
def form = new RegistrationForm(emailAddress: "ken.bad#gmail", password: "secret", confirmPassword: "wrong")
form.validate()
assert 1 == form.errors.getErrorCount()
}
Try just testing the RegistrationForm command object first in its own unit test. (gain some confidence that its actually working)
Maybe using the above for the basis of your test will help!?!?