I'm trying to mock the Sql instance in Groovy the following way, I'm using the spock framework for testing. However the test fails, please see below:
class SQLStatsStorageManagerTest extends Specification {
def mockSql
def setup() {
mockSql = GroovyMock(Sql, global: true)
}
void "SQLStatsStorageManager instantiation succeed"() {
def c
when: "SQLStatsStorageManager is instantiated"
c = new SQLStatsStorageManager("test", [hostname: "localhost", port: 666, database: "db", login: "root", password: "pass"])
then: "there is no error and name is set"
1 * mockSql.newInstance('jdbc:mysql://localhost:666/db', 'root', 'pass', 'com.mysql.jdbc.Driver')
assert c.getName() == "test"
}
}
The test fails with the following error:
Too few invocations for:
1 * mockSql.newInstance('jdbc:mysql://localhost:666/db', 'root', 'pass', 'com.mysql.jdbc.Driver') (0 invocations)
Unmatched invocations (ordered by similarity):
1 * mockSql.newInstance(jdbc:mysql://localhost:666/db, 'root', 'pass', 'com.mysql.jdbc.Driver')
Any idea ?
Thanks.
Pay attention to the fact that the only argument that does not match is db link.
You try to verify it as an instance of String:
'jdbc:mysql://localhost:666/db'
but in unmatched invocation it is:
jdbc:mysql://localhost:666/db
so here's the question, what it actually is? Verify the types and you'll have the problem solved.
Related
I have a simpler controller method that does the following:
def updateName(){
def idUser = params.id
User changeUser = User.get(idUser)
changeUser.name = "newname"
changeUser.save(flush: true)
}
And the following Spock test:
def "updateName should edit user and save it"(){
given: "the id of the user"
User currentUser = new User([name: "hector" , age: 12]).save(flush: true)
params.id = User.last().id
when: "the updateName method is called"
controller.updateName()
then: "name should have change it and save has to be called just one time"
assert currentUser.name == "newname" // Success
1 * _.save() // Too few invocations, 0.
}
I have seen all the related questions in SO about this topic, and people suggest using Mocks and Spy, but I don't really see why should I be using them and anyway I didn't get them to work for me, I tried to create a User mock and change my cardinality assert to:
1 * userMock.save()
But it didn't work for me... can I have some help with this?
To make it work, I create a GroovyMock that allows me to access to static functions such as save.
def "updateName should edit user and save it"(){
given: "the id of the user"
params.id = 1
User mockUser = GroovyMock(User, global: true)
when: "the updateName method is called"
controller.updateName()
then: "set Name and save has to be called just one time"
1 * User.get(1) >> mockUser
1 * mockUser.setName("newname")
1 * mockUser.save()
} //All test passed!
Not sure if it's the best way to do it, but it works for me! I'll leave the question in case someone offers a better solution, or throws some good information about this
I am using Grails v3.3.9.
I cannot get queries to eagerly load one-to-many association. Tried all sorts of ways.
This is posted relative to trying to use this in unit testing (fails on app at runtime as well).
Scenario: I have two domain classes, one called 'OrgRoleInstance' which has Collection<Site> sites, and static hasMany =[sites:Site], and the other called 'Site' which has a static belongsTo = [org:OrgRoleInstance].
This is birdirectional one-to-many from orgs to sites.
I create a new unit test using the new DomainUnitTest trait. In the test setup I create three orgs and add one site each, then I add one last site to the 3rd org (org "C"). Setup works fine and all instances are persisted.
In the where query test, I look for an Org that has 2 sites (which is org "C").
When I run the test in debug, the where query returns an array of size 1 containing org "C", so the test in the where clause can see that sites collection is not null - so far so good.
I also do a direct Site.get(4) to get the last site. I do an assert check to check that the sites.org ref is same instance returned from the where query. This is true and passes.
However when you look at the orgs[0] entry the sites collection is null. That simple println fails with accessing null sites property returned from the query.
class OrgRoleInstanceSpec extends Specification implements DomainUnitTest<OrgRoleInstance> {
def setup() {
OrgRoleInstance
List<OrgRoleInstance> orgs = []
["A","B","C"].each {
OrgRoleInstance org = new OrgRoleInstance(name:it, role:OrgRoleInstance.OrgRoleType.Customer)
org.addToSites(new Site( name: "$it's Head Office", status:"open", org:org))
orgs << org
}
orgs[2].addToSites (new Site( name: "${orgs[2].name}'s Branch Office", status:"open", org:orgs[2]))
OrgRoleInstance.saveAll(orgs)
assert OrgRoleInstance.count() == 3
println "# of sites : " + Site.count()
assert Site.count() == 4
assert Site.get(2).org.id == orgs[1].id
}
void "where query and individual get " () {
given :
def orgs = OrgRoleInstance.where {
sites.size() == 2
}.list(fetch:[sites:"eager"])
def org = OrgRoleInstance.get(2)
List orgSites = org.sites
def branch = Site.get(4)
assert branch.org.is (orgs[0]) //assert is true
println orgs[0].sites[1].name //orgs[0].sites is null !
expect:
orgs.size() == 1
}
}
I have tried this withCriteria, with basic findAll(fetch:[sites:"eager") etc.
However I try this I cannot get query to return eager populated collection of sites.
I want to do that in the queries rather than by mapping clause in OrgeRoleInstance domain class
Update/observations
I enabled SQL logging and started the grails console. I then typed the following script (using my bootstrap data).
Manually typed console script
import com.softwood.domain.*
def orgs = OrgRoleInstance.where {
id == 4
sites{}
}.list() /* (fetch:[sites:"eager"]) */
println orgs[0].sites
which when run outputs the following - which basically does seem to run eager selection - and I get the orgs.sites result with populated entries using an inner join:
groovy> import com.softwood.domain.*
groovy> def orgs = OrgRoleInstance.where {
groovy> id == 4
groovy> sites{}
groovy> }.list() /* (fetch:[sites:"eager"]) */
groovy> println orgs[0].sites
2019-01-23 14:02:00.923 DEBUG --- [ Thread-18] org.hibernate.SQL :
select
this_.id as id1_16_1_,
this_.version as version2_16_1_,
this_.role as role3_16_1_,
this_.name as name4_16_1_,
sites_alia1_.id as id1_21_0_,
sites_alia1_.version as version2_21_0_,
sites_alia1_.org_id as org_id3_21_0_,
sites_alia1_.name as name4_21_0_,
sites_alia1_.status as status5_21_0_
from
org_role_instance this_
inner join
site sites_alia1_
on this_.id=sites_alia1_.org_id
where
this_.id=?
2019-01-23 14:02:00.923 TRACE --- [ Thread-18] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [4]
2019-01-23 14:02:00.923 DEBUG --- [ Thread-18] org.hibernate.SQL :
select
sites0_.org_id as org_id3_21_0_,
sites0_.id as id1_21_0_,
sites0_.id as id1_21_1_,
sites0_.version as version2_21_1_,
sites0_.org_id as org_id3_21_1_,
sites0_.name as name4_21_1_,
sites0_.status as status5_21_1_
from
site sites0_
where
sites0_.org_id=?
2019-01-23 14:02:00.923 TRACE --- [ Thread-18] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [4]
[Site:(name : 1 Barkley Square) belonging to org: com.softwood.domain.OrgRoleInstance : 4, Site:(name : 10 South Close) belonging to org: com.softwood.domain.OrgRoleInstance : 4]
So why doesn't this work in unit testing?
Another update
I went back to grails console and managed to get this criteria query to work. Point 1 - you have to have imported org.hibernate.FetchMode, then the fetchMode function at root level in withCriteria closure will work now. Lastly just do empty closure on the collection to force the eager query.
import com.softwood.domain.*
import org.hibernate.FetchMode
def orgs = OrgRoleInstance.withCriteria {
fetchMode ("sites", FetchMode.SELECT)
sites{}
}
println orgs[0].sites
However this does not work in a unit test. The same query in unit test like this
void "criteria query " () {
given:
OrgRoleInstance org
org = OrgRoleInstance.withCriteria (uniqueResult: true) {
fetchMode ("sites", FetchMode.SELECT)
sites{}
}
expect:
org.id == 3
org.sites.size() == 2
}
fails with this error
groovy.lang.MissingMethodException: No signature of method: grails.gorm.CriteriaBuilder.fetchMode() is applicable for argument types: (java.lang.String, org.hibernate.FetchMode) values: [sites, SELECT]
I suspect therefore that unit testing criteriaQueries or where queries using the new grails DomainUnitTest<T> trait doesn't support join/eager queries etc.
It maybe that you're forced to integration tests with real DB to test queries across tables. If anyone can state categorically state that the new unit testing traits don't work for join/eager queries that might help me.
The output of this investigation is that you can't use unit testing for domain model queries that try to join tables using the new unit testing traits.
If you want to query testing you have to do it as integration tests.
When I re-coded my queries this time as integration tests, allowing for bootstrap data that gets loaded before any data in the spock setup() method, then the queries start to work and including eager queries for data.
One thing to remember is that the setup() method doesn't do a rollback (so that the data stays throughout the tests) so you should do a manual clear up at the end if your database is not getting dropped.
So this is no coded as integration test and appears to work!
package com.softwood.domain
import grails.testing.mixin.integration.Integration
import grails.transaction.*
import org.hibernate.FetchMode
import org.hibernate.LazyInitializationException
import spock.lang.Shared
import spock.lang.Specification
#Integration
#Rollback
class OrgRoleInstanceIntegSpecSpec extends Specification {
//operates on separate transaction thats not rolled back
#Shared
List<OrgRoleInstance> orgs = []
#Shared
List<OrgRoleInstance> sites = []
#Shared
NetworkDomain netDomain
#Shared
def bootstrapPreExistingOrgsCount, bootstrapPreExistingSitesCount
//runs in transaction thats not rolled back for each test
def setup() {
def site
bootstrapPreExistingOrgsCount = OrgRoleInstance.count()
bootstrapPreExistingSitesCount = Site.count()
//println "pre exist orgs:$boostrapPreExistingOrgsCount + pre exist sites: $boostrapPreExistingSitesCount"
assert bootstrapPreExistingOrgsCount == 4
assert bootstrapPreExistingSitesCount == 2
["A","B","C"].each {
OrgRoleInstance org = new OrgRoleInstance(name:"test$it", role:OrgRoleInstance.OrgRoleType.Customer)
org.addToSites(site = new Site( name: "test$it's Head Office", status:"open", org:org))
orgs << org
sites << site
}
orgs[2].addToSites (site = new Site( name: "${orgs[2].name}'s Branch Office", status:"open", org:orgs[2]))
orgs[2].addToDomains(netDomain = new NetworkDomain (name:"corporate WAN", customer:[orgs[2]]))
sites << site
OrgRoleInstance.saveAll(orgs)
assert orgs.size() == 3
assert sites.size() ==4
assert OrgRoleInstance.count() == 3 + bootstrapPreExistingOrgsCount
assert Site.count() == 4 + bootstrapPreExistingSitesCount
assert Site.get(4).org.id == orgs[1].id
println "setup integration test data"
}
//manual cleanup of integration test data
def cleanup() {
orgs.each {OrgRoleInstance org ->
org.sites.each {it.delete()}
org.delete(flush:true)
assert OrgRoleInstance.exists(org.id) == false
}
println "deleted integration test data"
}
void "Orgs list with eager fetch query"() {
given :
def orgs = OrgRoleInstance.list(fetch:[sites:"eager"])
println "org ${orgs[6].name} sites : " + orgs[5].sites
println "test site #2 has org as : " + (Site.list())[3].org
expect :
Site.count() == 4 + bootstrapPreExistingSitesCount
orgs.size() == 3 + bootstrapPreExistingOrgsCount
orgs[5].getName() == "testB"
orgs[5].sites.size() == 1
}
void "orgs where query triggering eager site get"() {
given :
//where clause returns instance of DetachedCriteria, so have to trigger with a list/get etc
def orgs = OrgRoleInstance.where {
name =~ "%testB%" &&
sites{}
}.list()
expect :
orgs.size() == 1
orgs[0].name == "testB"
orgs[0].sites.size() == 1
}
void "withCriteria query with eager site fetch (two selects) " () {
given:
OrgRoleInstance org
//with criteria runs the query for you unlike createCriteria() which returns a detachedCriteria
org = OrgRoleInstance.withCriteria (uniqueResult: true) {
fetchMode ("sites", FetchMode.SELECT)
idEq(7L) //internally wont cast Integer to long, so set it explicitly
sites{}
}
/*def orgs = OrgRoleInstance.withCriteria {
//setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
eq 'name', "B"
//fetchMode 'sites', FetchMode.SELECT
sites{}
}*/
expect:
org.id == 7
org.sites.size() == 2
}
void "detached criteria (with distinct) with eager fetch " () {
given:
def orgs = OrgRoleInstance.createCriteria().listDistinct {
//fetchMode 'sites', FetchMode.SELECT
join 'sites'
sites {
org {
eq 'id', 6L
}
}
}
def site = orgs[0].sites[0]
expect:
orgs.size() == 1
orgs[0].sites.size() == 1
site.name == "testB's Head Office"
}
void "where query on id only without list (fetch eager) " () {
given :
def orgs = OrgRoleInstance.where {
id == 7L
}.list ()
def branch = orgs[0].sites[0]
when:
println "branch "+ branch.name //try and access branch
then:
/*
-- seems to do an eager fetch on sites+domains, even though i didnt ask it to
not quite sure why - separate exploration round that i think
*/
//LazyInitializationException ex = thrown()
orgs.size() == 1
orgs[0].sites.size() == 2
orgs[0].domains.size() == 1
}
}
I hope this saves others from some heartache over why your tests don't work.
Note also that running grails console will fire up the console script app but boots a gorm build with it- so with judicious use of include domain packages - you can try out some test queries interactively against any bootstrap data that got loaded when gorm starts.
Integration tests are more laborious and costly in time to run.
It would be nice (and clever) if the unit testing traits could be enhanced to support query testing.
I have a set of basic unit tests in grails and I am getting some strange, inconsistent behaviour. So basically the unit tests are for a Service for interacting with my User Domain.
The issue is at a high level - If I run the full Spec of tests - 4 tests fail each time. If I run them individually - they pass. The obvious thing here is that there is state being held between tests - but given this is a unit test - there shouldn't be (and I have verified that with logging).
The components in play here are:
UserService
User Domain
Address Domain
UserCommand (Verifiable)
So looking at the Spec I have the following in setup:
User user
def setup() {
println "================ Setting Up User (${User.count()}) ================"
// Set the roles
new Role(authority: "ROLE_ADMIN").save()
new Role(authority: "ROLE_OPERATOR").save()
def role = new Role(authority: "ROLE_USER").save()
def userAddress = new Address()
userAddress.with {
name = "Name"
address1 = "Address 1"
address2 = "Address 2"
townCity = "Town"
postcode = "BT19"
county = "Down"
}
// Create an admin user
user = new User()
user.with {
christianName = "Phil"
surname = "Preston"
email = "p#p.com"
username = "admin"
password = "password123"
phone = ""
skype = ""
address = userAddress
}
println(user.properties)
// Save the test user
if (user.validate()) {
println "Saving"
user.save(flush: true, failOnErrors: true)
UserRole.create(user, role)
}
else {
user.errors.allErrors.eachWithIndex { i, x ->
println "${i} - ${x}"
}
}
assert user
}
And the two simple tests are as follows:
void "Test updateUser - changing a user password"() {
given: "An update to the user"
UserCommand cmd = new UserCommand()
cmd.with {
id = user.id
christianName = user.christianName
surname = user.surname
username = user.username
email = user.email
skype = user.skype
phone = user.phone
password = "newPassword"
passwordCheck = "newPassword"
isAdmin = user.isAdmin()
isOperator = user.isOperator()
}
when: "attempt to update"
User updated = service.updateUser(cmd)
then: "the password should be update - but nothing else"
updated.password == cmd.password
}
void "Test updateUser - changing a user detail"() {
given: "An update to the user"
UserCommand cmd = new UserCommand()
cmd.with {
id = user.id
christianName = user.christianName
surname = user.surname
username = user.username
email = "update#update.com"
skype = user.skype
phone = user.phone
password = user.password
isAdmin = user.isAdmin()
isOperator = user.isOperator()
}
when: "attempt to update"
User updated = service.updateUser(cmd)
then: "the email should be update - but nothing else"
updated.email == cmd.email
}
(There are others - but this is all to demonstrate the problem)
So the strangeness is as follows:
The first test passes, the second one fails.
If I swap the order - the first one still passes, second fails
If I run both individually - they both will pass
The code in setup() prints the number of User objects (0) each time
It verifies the object is created each time (assert and logging)
The unit test fails because I throw an exception when validation fails forthe User domain object I am udating. So the following:
def updateUser(UserCommand userCommand) {
assert userCommand
// Get the current
User foundUser = User.findById(userCommand.id)
def wasAdmin = foundUser.admin
def wasOperator = foundUser.operator
// Bind Data
bindData(foundUser, userCommand, ['class', 'operator', 'admin', 'address'])
foundUser?.address?.with {
name = userCommand.name
address1 = userCommand.address1
address2 = userCommand.address2
townCity = userCommand.townCity
county = userCommand.county
postcode = userCommand.postcode
}
// THIS VALIDATION FAILS ON SECOND TEST
if (foundUser.validate()) {
foundUser.save()
// ... removed
return foundUser.refresh()
}
else {
Helper.copyErrorToCmd(foundUser, userCommand)
log.error("Errors: ${foundUser.errors.allErrors}")
throw new UserServiceException(cmd: userCommand, message: "There were errors updating user")
}
The errors on the User domain object are basically (shortened):
'skype': rejected value [null]
'phone': rejected value [null]
So you can see that I have empty strings for these fields - and with conversion to null (as Grails will do), this is the reason. However the issue with that is:
It should fail for both, and certainly fail when run individually
Both fields are marked as nullable: true in the constraints
In UserService I have used the debugger to check the objects that are being saved when running both tests - the phone and skype are null for both tests, yet one fails and one doesn't
So the constraints in the User domain object are as follows:
static constraints = {
christianName blank: false
surname blank: false
username blank: false, unique: true, size: 5..20
password blank: false, password: true, minSize: 8
email email: true, blank: false
phone nullable: true
skype nullable: true
address nullable: true
}
And I am using a Command object which has the following constraints:
static constraints = {
importFrom User
importFrom Address
password blank: false, password: true, minSize: 8
passwordCheck(blank: false, password: true, validator: { pwd, uco -> return pwd == uco.password })
}
Note I have even tried adding the Skype and phone fields in the UserCommand constraints closure as well.
This issue goes away if I add text to the fields in setup, but thats not going to possible in the actual app as these fields can be left blank.
Any help on how this inconsistency happens would be greatly appreciated.
RECREATION
I have added a minimal GitHub project which recreates the issue: Github Project Recreating Issue. To see the problem:
./grailsw test-app
Will run the two test, first passes second fails. To run the failed test individually run:
./gradlew test --tests "org.arkdev.bwmc.accountmission.UserServiceSpec.*Test updateUser - changing a user detail"
And you can see the test pass.
The issue seems to be that the skype and phone fields are nullable:true for the first test, and nullable:false on the second test (I step into user.validate(), and step into the GrailsDomainClassValidator.java, in the validate(Object,Errors,boolean) call I can see the constrainedProperties Map (which is basically field -> constraints). This shows that skype is NullableConstraint.nullable == true, on the first call of setup, but is showing that NullableConstraint.nullable == false on the setup call for the second test.). This makes no sense.
After the first call
bindData(foundUser, userCommand, ['class', 'operator', 'admin', 'address'])
in UserService.updateUser(UserCommand) (called by feature method Test updateUser - changing a user password) the static member User.constraints becomes null. Go figure. I have no idea whatsoever how Grails works, so maybe someone else can make sense of it. But to me it seems that this should not happen. Maybe you are somehow making a mistake in that call.
You shouldn't have to test the constraints in the framework technically but I've had similar issues before so I can see why you would want to.
Is it possible to post your full test? Are you using #TestFor/#Mock at all? Just as a check, but I assume you must have #Mock otherwise you would get a different error creating the domain classes? #Mock is required for the constraints to be used (or #GrailsUnitTestMixin afaik).
You say in your comment "The values in your app can be blank"; it should be noted that this is not the same as nullable as well. If it really can be blank you should change/add it and then "" will work
You also are not using 'failOnError: true' as you have typoed it.
Sorry I don't have enough rep to write as a comment.
Currently searching for tutorials, explanations and examples.
I've tried different examples and came up to different errors.
My current error is :
| Error Compilation error compiling [unit] tests: startup failed:
and in my test reports. It outputs this :
Unit Test Results - Summary
No tests executed.
My "UserSpec.groovy" code is this :
package newmyproject245
import grails.test.mixin.*
import spock.lang.Specification
#TestFor(User)
class UserSpec extends ConstraintSpecification {
def setup() {
Expectations.applyTo User
}
def cleanup() {
}
void testShouldDoNothing() {
Expectations.applyTo User
user."password is not blank"
user."password is not nullable"
user."name is not blank"
user."name is not nullable"
}
void testEventNameConstraints() {
Expectations.applyTo User
def user = new User()
user."name is not blank"
user."name is not nullable"
}
}
Can anybody help. I'm new in grails.
Thanks!
Additional to the above problem,
when I omitted the Contraints in class as shown :
class UserSpec extends Specification {
I came up to this error :
| Running 1 unit test... 1 of 1
| Failure: initializationError(org.junit.runner.manipulation.Filter)
| java.lang.Exception: No tests found matching grails test target
pattern filter from org.junit.runner.Request$1#12c27788
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:35)
at org.junit.runner.JUnitCore.run(JUnitCore.java:138)
| Completed 1 unit test, 1 failed in 0m 0s
| Error Fatal error running tests: Not-null property references a transient value - transient instance must be saved before current operation : newmyproject245.Order.product -> newmyproject245.Product; nested exception is org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : newmyproject245.Order.product -> newmyproject245.Product (Use --stacktrace to see the full trace)
someone help. Again, Thanks!
I already got the answer. See code for reference :
UserSpec.groovy
package project101
import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import spock.lang.Specification
/**
* See the API for {#link grails.test.mixin.support.GrailsUnitTestMixin} for usage instructions
*/
#TestMixin(GrailsUnitTestMixin)
#TestFor(User)
class UserSpec extends Specification {
def user
def setup() {
user = new User(firstName: 'FIRSTNAME', lastName: 'LASTNAME', address: 'Finland', username: 'user1', password: 'pass123', userType: 'ADMIN')
}
def cleanup() {
user = null
}
void "Test if User handles"() {
given:
setup()
when: "User field has null value"
user?.username = null
then: "Validation returns false"
user?.validate() == false
user?.errors?.hasFieldErrors('username') == true
}
}
And make sure that the dbCreate of the test environment is "create-drop" to avoid such errors. Found in DataSource.groovy
test {
dataSource {
pooled = true
dbCreate = "create-drop"
Regards,
Thanks! (^_~)
I am trying to be a good little programmer and set up Unit tests for my Grails 2.2.3 app. The unit tests that use GORM's injected .save() method are apparently not persisting to the mock test DB. For an example, here is what one test consists of:
#TestFor(TermService)
#Mock(Term)
class TermServiceTests {
void testTermCount() {
def t = new Term(code: "201310").save(validate: false, flush: true, failOnError: true)
println "Printing Term: " + t.toString()
assert 1 == Term.count() // FAILS
assert service.isMainTerm(t) // FAILS
}
}
I did a println that ends up printing Printing Term: null, meaning the Term did not save and return a Term instance. The first assertion is false with Term.count() returning 0.
Does anyone know why this might be? I have a mock Term and TermService (via the TestFor annotation, I believe), so I'm not quite sure why this wouldn't work. Thanks!
Edit: Here is my Term class.
class Term {
Integer id
String code
String description
Date startDate
Date endDate
static mapping = {
// Legacy database mapping
}
static constraints = {
id blank: false
code maxSize: 6
description maxSize: 30
startDate()
endDate()
}
}
Looks like id generator is assigned since you have mentioned about using legacy database. Plus id is not bindable by default in domain class (map construct won't work for id). So, I think you have to end up using like below:
def t = new Term(code: "201310")
t.id = 1
t.save(...)