I am new to groovy and Spock.
I'm trying to create a generic method for mocking objects in my system.
the problem
I'm trying to create a function that will get an object and dynamically mock the functions I want in the object.
the function gets a map of functions with data when to mock each of one them and what to return.
the functions return an error.
I created a class
class MetaData {
Object[] argTypes
def returnValue
Object[] argsMatchers
MetaData(Object[] argTypes, returnValue, Object[] argsMatchers) {
this.argTypes = argTypes
this.returnValue = returnValue
this.argsMatchers = argsMatchers
}
}
the mocking function is:
def mockFunctionTestData(Map overrides = [:], def clazz){
def args = Mock(clazz)
overrides.each { String key, value ->
Object[] argTypes = value.argTypes
if(args.metaClass.respondsTo(args, key, argTypes).size() == 1){
def methodToGetRequest = key
def argsMatchers = value.argsMatchers
def returnValue = value.returnValue
args."$methodToGetRequest"(*argsMatchers) >> returnValue
} else {
println "Error: Trying to add property that doesn't exist"
}
}
return args
}
I'm creating the object :
def functionData = new MetaData([Date, Date, List, boolean] as Object[],
meas,
[_ as Date, _ as Date, new ArrayList<>(), true] as Object[]) //the line that fails
def dogDAO = [getDogData: functionData]
def testDog= mockFunctionTestData(dogDAO , Dog)
the code above returns the following exception:
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '_' with class 'org.spockframework.lang.Wildcard' to class 'java.util.Date' due to: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: java.util.Date(org.spockframework.lang.SpreadWildcard)
the line that fails
[_ as Date, _ as Date, new ArrayList<>(), true] as Object[])
In Spock Framework, you can't create a mock in such a dynamic fashion. Spock has its own compiler (AST Transformation to be precise) which creates an executable test code. Only when in interaction section, does it recognize "_" as a wildcard symbol and ">>" operator to return a fixed value. That's why you get that exception. Because "_" wildcard is not in an interaction section. I'd suggest writing your test similar to the following:
class DogSpec extends Specification {
def "test the dog"() {
when:
def dog = Mock(Dog) {
1 * getDogData(_ as Date, _ as Date, new ArrayList<>(), true) >> "Bark"
}
then:
dog.getDogData(new Date(), new Date(), [], true) == "Bark"
}
}
Where to declare interactions
Declaring Interactions at Mock Creation Time
Returning Fixed Values
Related
I could use some advice in how to mock an auto wired dependency used in a Grails unit test. I've omitted most of the unnecessary code and just given the test class and the relevant methods in the file class under test
class UserService {
def springSecurityService // spring bean
def passwordEncoder // auto wired as per
//https://stackoverflow.com/questions/33303585/spring-//security-encode-password-with- bcrypt-algorithm
.....
def passwordPreviouslyUsed(String newPassword, def userId){
def passwordExists = false
def usersPasswords = findPasswordsForUser(userId)
usersPasswords.each{ password ->
if (passwordEncoder.isPasswordValid(oldPassword, newPassword, null)) {
passwordExists = true
}
}
return passwordExists
}
.....
def findPasswordsForUser(def userId){
User foundUser = User.findById(userId)
def passwordsForUser = UserPasswords.createCriteria().list {
eq('user', foundUser)
projections{
property('password')
}
}
passwordsForUser
}
My test
class UserServiceSpec extends Specification implements DataTest, ServiceUnitTest<UserService> {
def passwordEncoder
def setupSpec() {
mockDomains User, UserPasswords
}
def setup() {
def stubPasswordEncoder = Stub(passwordEncoder) {
isPasswordValid(_, _, _) >> true
}
service.passwordEncoder = stubPasswordEncoder
}
void "test for user passwordPreviouslyUsed"() {
given: "a user already exists"
setup()
service.createNewUser("testName", "testy#test.com", "Secret1234" )
//^(does some validation, then User.save())
User foundUser = User.findByEmail("testy#test.com")
foundUser.fullName == "testName"
long testUserId = foundUser.id
and: "we update the password for that user, and it to the userPasswords"
UserPasswords newUserPassword = new UserPasswords(
user: foundUser,
password: "newPassword1"
)
newUserPassword.save()
//use passwordPreviouslyUsed method to check a string with the same value as the
//previously
//updated password to check if it has already been used
when: "we check if the password has been used before"
def response = service.passwordPreviouslyUsed("newPassword1", fundsyId)
then:
response == true
}
Without stubbing or mocking this dependency, I get the error
Cannot invoke method isPasswordValid() on null object
I tried to stub password encoder and have it return true
def stubPasswordEncoder = Stub(passwordEncoder) {
isPasswordValid(_, _, _) >> true
}
service.passwordEncoder = stubPasswordEncoder
But this gives an error message:
Stub in 'spock.mock.MockingApi' cannot be applied to '(java.lang.Object, groovy.lang.Closure)'
Is there any way to mock this dependency with Spock?
Stub and Mock take a class - you're giving it an instance that is null - hence the exception.
You should be able to mock it as so:
def mockPasswordEncoder = Mock(PasswordEncoder)
// note this is the class
// org.springframework.security.crypto.password.PasswordEncoder
I tried enrichelgeson's approach, and it worked!
I first imported PasswordEncoder to the test class
import org.springframework.security.crypto.password.PasswordEncoder
then implemented the normal mocking procedure. I was initially confused because they class under test just implicitly created an instance of the class by defining it.
def stubPasswordEncoder = Stub(PasswordEncoder) {
isPasswordValid(_, _, _) >> true
}
service.passwordEncoder = stubPasswordEncoder
I also found another solution that didn't require mocking
service.passwordEncoder = [ isPasswordValid: { String rawPass, String salt, Null -> true } ]
Both approaches work fine. Thanks for the help!
Here is what I have so far:
def "If there are results then return true otherwise return false"() {
given:
ResultSet resultSet = Mock()
expect:
resultSet.next()
}
I am trying to test a boolean method checkIfRowExists(int id, int foreignKey) in class CheckActuateProjectSetServiceImpl. It returns true if row exists and false otherwise.
How would I go about solving this?
public boolean checkIfRowExists(int id, int foreignKey){
Resultset resultSet = checkIfRowExistsResultSet(id, foreignKey)
return false;
}
The above method doesn't have the correct implementation as of yet because I'm trying to write the test first before I implement the solution.
Thanks
If I were on your place I would do the next TDD steps.
Start with a test for one test case only:
def "If there not are results then return false"() {
given:
def service = new CheckActuateProjectSetServiceImpl()
expect:
!service.checkIfRowExists(1, 2)
}
Implement the method to satisfy the test:
boolean checkIfRowExists(int id, int foreignKey) {
return false;
}
Add new test for case when there are some result:
def "If there are results then return true"() {
given:
def service = new CheckActuateProjectSetServiceImpl()
expect:
service.checkIfRowExists(1, 2)
}
Now we are forced to implement our method. The method will do a DB query and check the actual result set for emptiness. Because the DB query is out of unit test scope we extract it to a separate method and will override it in the test later:
boolean checkIfRowExists(int id, int foreignKey) throws SQLException {
ResultSet resultSet = getResultSet(id, foreignKey);
return resultSet.next();
}
ResultSet getResultSet(int id, int foreignKey) {
return null; // TODO should be implemented
}
Now our test is failed with NullPointerException because getResultSet() returns null. Lets return a mocked ResultSet which returns true on next() call:
def "If there are results then return true"() {
given:
ResultSet mockedResultSet = Mock(ResultSet)
mockedResultSet.next() >> true
def service = new CheckActuateProjectSetServiceImpl() {
#Override
def ResultSet getResultSet(int id, int foreignKey) {
return mockedResultSet;
}
}
expect:
service.checkIfRowExists(1, 2)
}
The test is green now.
The first test is to be fixed as well, mock to return false on next() call:
def "If there not are results then return false"() {
given:
ResultSet mockedResultSet = Mock(ResultSet)
mockedResultSet.next() >> false
def service = new CheckActuateProjectSetServiceImpl() {
#Override
def ResultSet getResultSet(int id, int foreignKey) {
return mockedResultSet;
}
}
expect:
!service.checkIfRowExists(1, 2)
}
Hope it will help. These steps are just an orientation to move forward in TDD style. Sure things your reality is different and may require something more specific that I proposed above.
Am getting the following error message when testing the controller - see below for code.
How can I correct this?
When I invoke the service method from the controller (run-app) and it works fine.
Exception:
groovy.lang.MissingMethodException: No signature of method:
grails.test.GrailsMock.isOk() is applicable for argument types:
(java.lang.String) values: [H] at ...VControllerSpec.test
something(VControllerSpec.groovy:)
class: VControllerSpec
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(VController)
#Mock(VService)
class VControllerSpec extends Specification {
void "test something"() {
given:
def vServiceMock = mockFor(VService)
vServiceMock.demand.isOk { String yeah -> return true }
controller.vService = vServiceMock.createMock()
when:
def isO = vServiceMock.isOk("H")
then:
isO == true
}
}
class:VService
import grails.transaction.Transactional
#Transactional
class VService {
def isOk = { String yeah ->
def isO = false
return isO
}
}
Thanks,
Steve
Assuming there is an action in VController as:
def myAction() {
vService.isOk('Hello')
}
below test should pass
void 'test service'() {
given:
def vServiceMock = mockFor(FormatService)
vServiceMock.demand.isOk { String yeah -> return true }
controller.vService = vServiceMock.createMock()
when:
def isO = controller.myAction()
then:
isO == true
}
There are few things to optimize here including using a method isOk instead of a closure as best practices.
One is not expected to test a method which is being mocked. When we mock a method, we just assume its implementation is correct and has already been tested (in some other unit test). The purpose of mocking is to limit our focus of testing to limited lines of code (mostly commonly one method), in your case the your controller action. So the above test case could have been written as:
Assuming your action is like this:
def myAction(){
[iso: vServiceMock.isOk()] // assuming isOk returns boolean true
}
void "test myAction"() {
given:
def vServiceMock = mockFor(VService)
vServiceMock.demand.isOk { String yeah -> return true }
controller.vService = vServiceMock.createMock()
when:
def model = controller.myAction()
then:
model.iso //you can skip comparison with true
}
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.
Is it possible to test the sort propertyName which is defined in the staticMappingBlock?
This works during the integration phase but not during the unit phase where my domain has:
static mapping = {
sort 'lastName'
}
void testDefaultSortOrder(){
def agent1 = new CommissionAgent(firstName: 'fred', lastName: 'b', active:true).save()
def agent2 = new CommissionAgent(firstName: 'fred2', lastName:'a', active:false).save()
def agents = CommissionAgent.list()
assertEquals 'sort order is wrong', agents[0].lastName, agent2.lastName
assertEquals 'sort order is wrong', agents[1].lastName, agent1.lastName
}
Grails version is 1.3.1
There isn't any good way to test the actual sorting in unit tests that I'm aware of. What you're trying to test is really such an integral part of the GORM integration that testing it on mocked domain objects, even if they support the sort mapping, doesn't test the actual code that will be run.
The closest thing that you could do in a unit test would be to take a look at the static mapping object to assert that the value of "sort" is set to what you expect it to be.
I put together a blog post a while ago on how to interrogate groovy closures for values. This technique could be used to assert the sort order is set to what you expect like this:
Foo domain object:
package com.example
class Foo {
String name
static mapping = {
sort "name"
}
}
FooTests unit test:
package com.example
import grails.test.*
class FooTests extends GrailsUnitTestCase {
void testFooSort() {
def mappingValues = ClosureInterrogator.extractValuesFromClosure(Foo.mapping)
assertEquals "name", mappingValues.sort
}
}
ClosureInterrogator class that allows you to see what a closure does:
package com.example
class ClosureInterrogator {
private Map closureValueMap = [:]
static Map extractValuesFromClosure(Closure closure) {
def interrogator = new ClosureInterrogator(closure)
return interrogator.closureValueMap
}
private ClosureInterrogator(Closure closure) {
def oldResolveStrategy = closure.getResolveStrategy()
def oldDelegate = closure.getDelegate()
closure.delegate = this
closure.resolveStrategy = Closure.DELEGATE_FIRST
try {
closure()
} finally {
closure.setDelegate(oldDelegate)
closure.setResolveStrategy(oldResolveStrategy)
}
}
// property getter
def propertyMissing(String name) {
return closureValueMap[name]
}
// property setter
def propertyMissing(String name, value) {
closureValueMap[name] = value
}
def methodMissing(String name, args) {
if (args.size() == 1) {
closureValueMap[name] = args[0]
} else {
closureValueMap[name] = args
}
}
}