It seems docs for mongodb-1.1.0GA are outdated when it comes to unit testing section: http://springsource.github.com/grails-data-mapping/mongo/manual/ref/Testing/DatastoreUnitTestMixin.html
Following code
#TestFor(Employee)
class EmployeeTests extends GroovyTestCase {
void setUp() {
}
void tearDown() {
}
void testSomething() {
mockDomain(Employee)
def s = new Employee(firstName: "first name", lastName: "last Name", occupation: "whatever")
s['testField'] = "testValue"
s.save()
assert s.id != null
s = Employee.get(s.id)
assert s != null
assert s.firstName == "first name"
assert s['testField'] == "testValue"
}
}
fails with this error:
No such property: testField for class: Employee
Employee class is pretty straightforward:
class Employee {
String firstName
String lastName
String occupation
static constraints = {
firstName blank: false, nullable: false
lastName blank: false, nullable: false
occupation blank: false, nullable: false
}
}
So, is unit testing of dynamic attributes possible? If it is, how?
There's no out of the box support for dynamic attributes but it's fairly easy to add. I've put the following code in my setup method. It will add dynamic attributes to any domain classes you have enabled using #TestFor or #Mock.
grailsApplication.domainClasses.each { domainClass ->
domainClass.metaClass.with {
dynamicAttributes = [:]
propertyMissing = { String name ->
delegate.dynamicAttributes[name]
}
propertyMissing = { String name, value ->
delegate.dynamicAttributes[name] = value
}
}
}
Related
I am migrating a big project from grails 2.5.4 to 3.3.10. Everything is going well but I have a mayor problem in my domain objects. I use to write my custom validators this way:
class Person {
String name
static constraints = {
name: nullable: false, validator: validateName
}
static validateName = {
// validation code
}
}
Grails throws the following exception
No such property: validatorTest for class: org.grails.orm.hibernate.cfg.HibernateMappingBuilder
In grails 3.x this way of defining validators seems to be broken. I know the documentation says to use this way:
name nullable: false, validator: { // code }
But it is a LOT of code to rewrite in that case.
Is there a way to use the old method of defining validators?
Thanks
See the project at https://github.com/jeffbrown/alejandroveraconstraints.
https://github.com/jeffbrown/alejandroveraconstraints/blob/master/grails-app/domain/alejandroveraconstraints/Person.groovy:
// grails-app/domain/alejandroveraconstraints/Person.groovy
package alejandroveraconstraints
class Person {
String name
static constraints = {
name nullable: false, validator: Person.validateName
}
static validateName = {
it != 'Some Bad Name'
}
}
https://github.com/jeffbrown/alejandroveraconstraints/blob/6701f61d61dbbde34f4925d1bf418448eee0a729/src/test/groovy/alejandroveraconstraints/PersonSpec.groovy:
// src/test/groovy/alejandroveraconstraints/PersonSpec.groovy
package alejandroveraconstraints
import grails.testing.gorm.DomainUnitTest
import spock.lang.Specification
class PersonSpec extends Specification implements DomainUnitTest<Person> {
void "test validation"() {
expect:
!new Person(name: 'Some Bad Name').validate()
new Person(name: 'Some Good Name').validate()
}
}
I have a field in a domain class that I applied the blank: false constraint to and I write a unit test to verify that a spaces only string for the field doesn't pass the validation, but the test fails:
void 'test name cannot be blank'() {
when:
domain.name = ' '
then:
!domain.validate(['name'])
domain.errors['name'].code == 'blank'
}
I this the ConditionNotSatisfiedError error on the line !domain.validate(['name']): ConditionNotSatisfiedError
This is my domain object:
class Thing {
String name
static constraints = {
name nullable: false, blank: false, size: 1..20
}
}
You haven't indicate what version of Grails you are using and that will likely be relevant. The project at https://github.com/jeffbrown/selenablank demonstrates how this works in 3.3.3.
https://github.com/jeffbrown/selenablank/blob/master/grails-app/domain/selenablank/Thing.groovy
package selenablank
class Thing {
String name
static constraints = {
name nullable: false, blank: false, size: 1..20
}
}
https://github.com/jeffbrown/selenablank/blob/master/src/test/groovy/selenablank/ThingSpec.groovy
package selenablank
import grails.testing.gorm.DomainUnitTest
import spock.lang.Specification
class ThingSpec extends Specification implements DomainUnitTest<Thing> {
void 'test name cannot be blank'() {
when:
domain.name = ' '
then:
!domain.validate(['name'])
domain.errors['name'].code == 'blank'
}
}
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 this controller:
[HttpPost]
public ActionResult Create(Company company)
{
// try to save the record
if (ModelState.IsValid)
{
// create the command
var command = new CreateOrUpdateCompanyCommand
{
CompanyId = company.CompanyId,
Code = company.Code,
Name = company.Name
};
// check for errors
IEnumerable<ValidationResult> errors = _commandBus.Validate(command);
ModelState.AddModelErrors(errors);
if (ModelState.IsValid)
{
var result = _commandBus.Submit(command);
if (result.Success)
return RedirectToAction("Index");
}
}
// if fail
return View("Create", company);
}
I have this test for NUnit:
[Test]
public void Create()
{
const string expectedRouteName = "Index";
// Mock the arguments
var mockRepository = Substitute.For<ICompanyRepository>();
var mockProcessor = Substitute.For<ICommandBus>();
// Arrange
var controller = new CompanyController(mockProcessor, mockRepository);
// Act
var company = new Company
{
Code = "XXXXXXX",
CompanyId = 1,
Name = "Sample company"
};
var result = controller.Create(company) as RedirectToRouteResult;
// Assert
Assert.IsNotNull(result, "Should return a ViewResult");
Assert.AreEqual(expectedRouteName, result.RouteValues["action"],
"View name should have been '{0}'", expectedRouteName);
}
This is the Model:
public class Company
{
[Key]
public int CompanyId { get; set; }
[Required(ErrorMessage = "* (xxxx)")]
[MaxLength(7)]
[RegularExpression("^([A-Z0-9]{7})$", ErrorMessage = "xxx")]
[Display(Name = "Code")]
public string Code { get; set; }
[Required(ErrorMessage = "*")]
[MaxLength(40)]
[Display(Name = "Name")]
public string Name { get; set; }
}
When I Run the test, this function always return false: var result = _commandBus.Submit(command); and the test fails.
I don't know how to test it? Should I mock the _commandBus and set it to return true? I tried in this way but unsuccessfully:
var mockCommand = Substitute.For<ICommand>();
mockProcessor.Submit(mockCommand).Success.Returns(true);
To create this project I have got inspiration from this http://efmvc.codeplex.com/
Any advise to me? Thanks.
The command you pass to mockProcessor.Submit(mockCommand).Success.Returns(true) needs to be the same one that the code-under-test passes. As the method news up its own command this will never be the case.
Easiest fix is to match any command when you set up your substitute:
var result = CreateSuccessfulResult(); // <-- fill this in as appropriate
mockProcessor.Submit(null).ReturnsForAnyArgs(result);
Setting the Success field on result inline as per your original test should work too I think, but I find it a bit clearer to specify the result required.
You can improve this a bit by matching the expected command type:
mockProcessor.Submit(Arg.Any<CreateOrUpdateCompanyCommand>()).Returns(result);
You can also inspect the command passed if you'd like to test that:
mockProcessor
.Submit(Arg.Is<CreateOrUpdateCompanyCommand>(x => x.CompanyId = ...))
.Returns(result);
A similar approach can be used to check the Validate call.
There's a bit more info in the NSubstitute docs.
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.