How to mock springSecurityService in unit tests using grails - unit-testing

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
}]

Related

unit test fails with Failed assertion: line 17: '<optimized out>': is not true

I'm stuck with a unit test and fairly new to testing.
I tried to create a test for a class with toMap/fromMap methods and write tests for it.
Within the class I have the following code, where I added the hashCode and == operator methods to prepare the class for the test.
I have the exact same setup for other classes, where the test works..
String uid;
String email;
String userName;
String diagnose;
bool surgery;
List<Goal> goals;
List<KOS> kos;
UserCase({
this.uid,
this.email,
this.userName,
this.diagnose,
this.surgery = false,
this.goals,
this.kos,
});
factory UserCase.fromData(Map<String, dynamic> data) {
if (data == null) {
print('UserCase fromData NULL');
return null;
}
final String uid = data['uid'] ?? '';
final String email = data['email'] ?? '';
final String userName = data['userName'] ?? '';
final String diagnose = data['diagnose'] ?? '';
final bool surgery = data['surgery'] ?? false;
final List<Goal> goals = data['goals'] == null
? []
: List.from(data['goals'].map((e) => Goal.fromData(e)));
final List<KOS> kos = data['kos'] == null
? []
: List.from(data['kos'].map((e) => KOS.fromData(e)));
return UserCase(
uid: uid,
email: email,
userName: userName,
diagnose: diagnose,
surgery: surgery,
goals: goals,
kos: kos,
);
}
Map<String, dynamic> toMap() {
return {
'uid': uid,
'email': email,
'userName': userName,
'diagnose': diagnose,
'surgery': surgery,
'goals': goals == null || goals.isEmpty
? []
: goals.map((e) => e.toMap()).toList(),
'kos':
kos == null || kos.isEmpty ? [] : kos.map((e) => e.toMap()).toList(),
};
}
**UPDATE: adding hashList to ListObjects**
#override
int get hashCode => hashValues(
uid, email, userName, diagnose, surgery, hashList(goals), hashList(kos));
old:
*#override
int get hashCode {
return hashValues(uid, email, userName, diagnose, surgery, goals, kos);
}*
#override
bool operator ==(other) {
if (identical(this, other)) return true;
if (runtimeType != other.runtimeType) return false;
final UserCase otherCase = other;
return uid == otherCase.uid &&
email == otherCase.email &&
userName == otherCase.userName &&
diagnose == otherCase.diagnose &&
surgery == otherCase.surgery &&
goals == otherCase.goals &&
kos == otherCase.kos;
}
}
And this is the test that fails:
final userCase = UserCase.fromData({
'uid': 'id123',
'email': 'email123',
'userName': 'username',
'diagnose': 'ACL',
'surgery': true,
'goals': [],
'kos': [],
});
expect(
userCase,
UserCase(
uid: 'id123',
email: 'email123',
userName: 'username',
diagnose: 'ACL',
surgery: true,
goals: [],
kos: [],
));
});
**UPDATED ERROR MESSAGE after hashList has been added **
test/usercase_test.dart: fromData case with all properties [E]
Expected: UserCase:<uid: id123, email: email123, userName: username, diagnose: ACL, surgery: true, goals: [], kos: []>
Actual: UserCase:<uid: id123, email: email123, userName: username, diagnose: ACL, surgery: true, goals: [], kos: []>
package:test_api expect
package:flutter_test/src/widget_tester.dart 431:3 expect
usercase_test.dart 21:7 main.<fn>.<fn>```
And that is the error message - this one changed now to the one above, after adding the hashList method to the list properties.
.../test/usercase_test.dart: fromData case with all properties [E]
'dart:ui/hash_codes.dart': Failed assertion: line 17: '<optimized out>': is not true.
dart:ui hashValues
../lib/Classes/UserCase.dart 71:12 UserCase.hashCode
dart:collection _CompactLinkedHashSet.contains
package:matcher/src/pretty_print.dart 28:14 prettyPrint._prettyPrint
package:matcher/src/pretty_print.dart 119:22 prettyPrint
package:matcher/src/description.dart 49:11 StringDescription.addDescriptionOf
package:matcher/src/equals_matcher.dart 267:19 _DeepMatcher.describe
package:matcher/src/description.dart 47:13 StringDescription.addDescriptionOf
package:test_api expect
package:flutter_test/src/widget_tester.dart 431:3 expect
usercase_test.dart 22:7 main.<fn>.<fn>ยดยดยด
I can't see anything obvious suggesting which property is causing the test to fail.
A couple of suggestions:
Try removing one property at a time from the comparisons in the == implementation.
Try using the Equatable package for your model class. This reduces the boilerplate a lot and is less error-prone than implementing == and hashCode by hand.

Why doesn't a spaces only value for a field that has the blank: false constraint fail validation

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'
}
}

Grails Unit Test doesn't fail

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)
}

Is unit testing of mongodb dynamic attributes possible in Grails 2.2?

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
}
}
}

Unit testing custom validator of command object with dependency

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.