grails 2 integration test - grails

I have created an Integration Test in Grails 2.x with the purpouse of testing several controllers in order to simulate a complete user flow within a Web App.
First I saved two simple domain object records, instantiating two controller instances within my test case. This two simple classes are:
- Category (category of a product) and
- Store (mini market where products are sale)
I wrote two testing methods to control the controller instances (StoreController and CategoryController) and worked fine, one category record was created and several store records as well.
Then, I wrote a third method to try to save a Product record. This record must reference a Category. So, I take the category instance from previous methods and try to pass it to the ProductController among the other Product parameters.
For an unknown reason, I'm only able to create Product records through the web app instance typing the data in the web browsers, but not by the test class code.
I think the problem issue is with the relationship between Product and Category, but I could not figured out how I should pass the parameters to the ProductController from my test case in order to create a new Product record.
This is my Product class:
class Product {
int id
String barCode
String shortDesc
String longDesc
String format
Category category
static belongsTo = [category: Category]
//static hasManySurveyRecord = [surveyRecord: SurveyRecord]
static constraints = {
id editable: false
barCode blank: false, nullable: false, maxSize: 64
shortDesc blank: false, nullable: false, maxSize: 32
longDesc blank: false, nullable: false, maxSize: 128
category blank: false
}
static mapping = {
table 'product_catalog'
version false
columns {
id column: 'id'
barCode column: 'bar_code'
shorDesc column: 'short_desc'
longDesc column: 'long_desc'
format column: 'format'
}
}
String toString() {
return longDesc
}
}
This is my Category class:
class Category {
int id
String description
static hasManyProduct = [products: Product]
static constraints = {
id editable: false
description blank: false, nullable: false, maxSize: 64
}
static mapping = {
table 'categories'
version false
columns {
id column: 'id'
description column: 'description'
}
}
String toString() {
return description
}
}
This is my integration test for this app:
static transactional = false
static storeList = []
static storesData = []
static categoryIns
static categoryData = []
static productIns = new Product()
static productData = []
#Before
void setup() {
storesData.add([zipCode: 926260001, address: "first test avenue, first city, CA" , description: "first testing store"])
storesData.add([zipCode: 926260002, address: "second test avenue, second city, CA" , description: "second testing store"])
storesData.add([zipCode: 926260003, address: "third test avenue, third city, CA" , description: "third testing store"])
storesData.add([zipCode: 926260004, address: "fourth test avenue, fourth city, CA" , description: "fourth testing store"])
storesData.add([zipCode: 926260005, address: "fifth test avenue, fifth city, CA" , description: "fifth testing store"])
storesData.add([zipCode: 926260006, address: "sixth test avenue, sixth city, CA" , description: "sixth testing store"])
storesData.add([zipCode: 926260007, address: "seventh test avenue, seventh city, CA", description: "seventh testing store"])
storesData.add([zipCode: 926260008, address: "eighth test avenue, eighth city, CA" , description: "eighth testing store"])
categoryData = [description: "testing category"]
productData = [barCode: "0114B", shorDesc: "The short testing description", longDesc: "The long testing description ....", format: "1 LT"]
}
#Test
void _01__createStores() {
def storeCtl = new StoreController()
(0..7).each { i ->
def model = storeCtl.create()
assert model.storeInstance != null
storeCtl.response.reset()
storeCtl.params.putAll( storesData.get(i) )
storeCtl.save()
assert Store.count() == (i+1)
}
storeList.addAll( Store.list() )
assert storeList.size() == Store.list().size()
}
#Test
void _02__createCategory() {
// Test if there is a previous store list created
assert storeList.size() == Store.list().size()
def categoryCtl = new CategoryController()
def model = categoryCtl.create()
assert model.categoryInstance != null
categoryCtl.response.reset()
categoryCtl.params.putAll( categoryData )
categoryCtl.save()
assert Category.count() == 1
categoryIns = Category.list()[0]
}
#Test
void _03__createProduct() {
// Test if there is a previous store list created
assert storeList.size() == Store.list().size()
// Test if there is a previous category created
assert categoryIns != null
assert categoryIns.id > 0
def productCtl = new ProductController()
def model = productCtl.create()
assert model.productInstance != null
productCtl.response.reset()
productData.put("category", [id: categoryIns.id])
productData.put("category.id", categoryIns.id)
productCtl.params.putAll( productData )
//productCtl.params.category = Category.get(categoryIns.id)
productCtl.save()
assert Product.count() == 1
}
This is my ProductController code extract:
def save() {
def productInstance = new Product(params)
if (!productInstance.save(flush: true)) {
render(view: "create", model: [productInstance: productInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'product.label', default: 'Product'), productInstance.id])
redirect(action: "show", id: productInstance.id)
}

Both recomendations worked fine. After hours and hours trying to figure out what were going wrong, thanks to you I saw clear my silly silly mistake: a field "shortDesc" was misspelled as "shorDesc".
So, one little tip to my book has been written.
Thank you very much!

Related

Convert Sql Query to Grails/Gorm query

How do I convert the following SQL query to Grails/Gorm? Can this be done with a basic query? I would like to avoid using Criteria, Projections and HQL to keep it consistent with the structure of the other queries in my code base (which are basic queries).
SELECT dealer_group_user_dealer_users_id, COUNT(user_id)
FROM db.dealer_group_user_user
GROUP BY dealer_group_user_dealer_users_id;
And is it possible to perform the query in the gsp page to display the result for a specific user_id as opposed to running the query in the controller?
To update from a comment made, below is my domain classes.
class DealerGroupUser extends User{
static hasMany = [dealerUsers: User]
static constraints = {
}
}
class User {
transient authService
Boolean active = true
String firstName
String lastName
String title
String username
String emailAddress
String passwordHash
Date lastLoginTime
Date dateCreated
Date lastUpdated
Retailer dealer
Client client
Date passwordUpdated
Long dealerUser
Boolean isReadOnlyClientManager = false
String regionClientManager
// Transient properties
String fullName
String password
static transients = ['fullName', 'password']
static mapping = {
//permissions fetch: 'join'
sort firstName: 'asc' // TODO: Sort on fullName
}
static hasMany = [roles: Role, permissions: String]
static constraints = {
// NOTE: If a username is not provided, the user's email address will be used
firstName maxSize: 30, blank: false
lastName maxSize: 30, blank: false
title maxSize: 50, blank: false, nullable: true
username blank: false, unique: true
emailAddress email: true, unique: false, blank: false
passwordHash blank: false
lastLoginTime nullable: true
active nullable: true
dealer nullable: true
client nullable: true
passwordUpdated nullable: true
dealerUser nullable: true
regionClientManager nullable: true
}
void setEmailAddress(String emailAddress) {
if (EmailValidator.instance.isValid(emailAddress)) {
this.emailAddress = emailAddress
if (!username) {
username = emailAddress
}
}
}
static namedQueries = {
dealerGroupUsers {
eq 'class', 'com.db.torque.DealerGroupUser'
}
}
Integer setPassword(String plainTextPassword) {
plainTextPassword = plainTextPassword?.trim()
if (plainTextPassword) {
if (!plainTextPassword.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=\\S+\$).{8,}\$")){
return -1
}
String previousPassword = this.passwordHash
String newPassword = authService.encrypt(plainTextPassword)
if (previousPassword != newPassword) {
this.passwordHash = newPassword
return 1
}
else {
return -2
}
}
return -1
}
#Transient
public static List<User> findAllByRolesContains(Role role) {
return User.executeQuery("""
SELECT u
FROM User as u
WHERE :role IN elements(u.roles)
""", [role: role])
}
String fullName() {
return "${firstName} ${lastName}"
}
String toString() {
return fullName()
}
}
SELECT dealer_group_user_dealer_users_id, COUNT(user_id)
FROM db.dealer_group_user_user
GROUP BY dealer_group_user_dealer_users_id;
In your user class you have :
Retailer dealer
So lets start from the beginning what is query doing, listing users from user then getting a count of how many times user appears on Retailer domain class ?
The best way to do this would
be
String query = """ select
new map(
u.id as userId,
(select count(d) from DealerGroupUser d left join d.dealerUsers du where du=u) as userCount
)
From user u order by u.id
"""
def results = User.executeQuery(query,[:],[readOnly:true]
This should do what you are doing I think.
And is it possible to perform the query in the gsp page to display the
result for a specific user_id as opposed to running the query in the
controller?
Views are presentation layer and hardcore work should be kept out of it - if needed to use a TagLib call.
Controllers although used in grails examples and rolled out as part of defaults to make things easier also not the best place. You should be doing that in a service which is injected in a controller and presented in view as the actual model of what is needed.
That is the proper way - GSP have a runtime size - keep it short, keep it sweet

Inheritance In spock Framework. I want to reuse testing cases in multiple specs

In my project I have many domain objects that are very similar between each other. While designing the tests I realized that a lot of the test cases were identical. So I set myself to create a BaseSpec that would enable me to reuse logic and code.
Is the approach I describe below correct.
How would I execute all my unit tests except BaseSpec?
Suppose I have the following two grails domain classes:
class Product{
String productName
static constraints = {
name nullable: false, blank: false, unique: true
}
}
class Category{
String categoryName
static constraints = {
name nullable: false, blank: false, unique: true
}
}
First I would need a Spec to be used as a base. This base would have the common tests for both ProductSpec and Category Spec.
#Mock([Product, Category]) //? is this needed
class BaseSpec extends Specification {
#Shared classForTest
#Shared constructor
#Shared nameParam
def setup(){
//This is what I would override in my child Tests
//classForTest = new Category().getClass()
//constructor = classForTest.getConstructor()
//nameParam = "categoryName"
}
def "Testing that the name field is unique"(){
given: "A class instance"
String testValue = "ABSCSD SDS SDS"
def instance1 = constructor.newInstance() //using the constructor to get an instance
instance1."${nameParam}" = testValue
instance1.save(flush: true, failOnError: true)
and: "A duplicated Instance"
def instance2 = constructor.newInstance()
instance2."${nameParam}" = testValue
expect: "The second instance should not save"
shouldFail {instance2.save(flush: true, failOnError: true)}
}
//...Other common test cases
}
Then I would have a ProductSpec and a CategorySpec, and each should only override the setup of the BaseSpec.
#TestFor(Product)
class ProductSpec extends BaseSpec{
#Override
def setup(){
classForTest = new Product().getClass() //Get the class that is testec
constructor = classForTest.getConstructor() //Get the constructor of the tested class
nameParam = "productName" //Establish the name of the parameter
}
//... Other Product Tests
}
#TestFor(Category)
class CategorySpec extends BaseSpec {
#Override
def setup(){
classForTest = new Category().getClass()
constructor = classForTest.getConstructor()
nameParam = "categoryName"
}
//... Other Category Tests
}
This is an alternative to what I originally posted. It does not use inheritance but it will allow testing cases where the testing cases are very similar.
Consider the domain classes
class Product{
String productName
static constraints = {
name nullable: false, blank: false, unique: true
}
}
class Category{
String categoryName
static constraints = {
name nullable: false, blank: false, unique: true
}
}
As a very simple example we want to test the validation of productName and categoryName. So we could have a test like:
#Mock([Product, Category])
class CatalogSimpleGenericSpec extends Specification {
def "Validation of test field in a given domain"(){
given: "A new instance of the domain"
def testInstance = constructorOfInstance.newInstance() //Creating the instance using the constructor
testInstance."${fieldName}" = fieldValue
testInstance.validate()
expect: "Testing if the instance should save depending on the value of shouldHaveErrors"
assert testInstance.hasErrors() == shouldHaveErrors //Verifying if it should have errors
//If there are errors the instance should fail to save, otherwise it will save perfectly
shouldHaveErrors ?
shouldFail {testInstance.save(flush: true, failOnError: true)}
: testInstance.save(flush: true, failOnError: true)
where:
constructorOfInstance | shouldHaveErrors | fieldName | fieldValue | reasoning
//----------------- PRODUCT ----------------------
new Product().getClass().getConstructor() | false | "productName" | "Folders" | "Should pass since a product name is supplied"
new Product().getClass().getConstructor() | true | "productName" | "" | "Should fail empty strings should not be accepted"
new Product().getClass().getConstructor() | true | "productName" | null | "Should fail null values shoult not be accepted"
//----------------- CATEGORY --------------------
new Category().getClass().getConstructor() | false | "categoryName" | "Office Supplies" | "Should pass since a category name is supplied"
new Category().getClass().getConstructor() | true | "categoryName" | "" | "Should fail empty strings should not be accepted"
new Category().getClass().getConstructor() | true | "categoryName" | null | "Should fail null values shoult not be accepted"
}
}
Instead of using inheritance I am getting the constructor of an instance of the domain, and then using that constructor (constructorOfInstance) to build my instance (testInstance). The field value is assigned using testInstance."${fieldName}" = fieldValue. And we test wheter or not the save should fail using the value of shouldHaveErrors.

ElasticSearch in Grails, search return no results when domain field has value with # character

I encountered a problem when I was changing Searchable plugin to ElasticSearch plugin (:elasticsearch:0.0.3.8) for Grails (2.4.4).
Let's say that I have domain object and a service:
class Person {
String firstName
String lastName
String email
static constraints = {
id bindable: true
firstName blank: false
lastName blank: false
email blank: false, unique: true, email: true
}
static searchable = {
root true
only = ['id', 'firstName', 'lastName', 'email']
}
}
class SearchService {
List<Person> findPersons(String searchPhrase) {
Innovator.search(searchPhrase + '*').searchResults
}
}
My Config.groovy file contains following config:
elasticSearch {
client.mode = 'local'
index.store.type = 'memory'
date.formats = []
defaultExcludedProperties = ["password"]
disableAutoIndex = false
datastoreImpl = 'hibernateDatastore'
bulkIndexOnStartup = true
maxBulkRequest = 500
}
Suppose that we have following person in DB:
Person(firstName: 'Julius', lastName: 'Caesar', email: 'julius.caesar#domain.com')
Now, when I invoke findPersons('Julius') or findPersons('Caesar') or findPersons('Jul') etc. then as a result I get list with one Person object.
But when I try to search using phrase with '#' character for example: findPersons('julius.caesar#doma') or findPersons('julius.caesar#domain.com') I do not receive any results, hovever findPersons('julius.caesar') is ok.
Analogical code in Searchable plugin works correct.
I've tried to remove '*' character and it didn't help.
As workaround I changed searchable closure to:
static searchable = {
root true
email index : 'not_analyzed'
only = ['id', 'firstName', 'lastName', 'email']
}
and findPersons method to:
List<Person> findPersons(String searchPhrase) {
if(!searchPhrase.contains('#'){
searchPhrase += '*'
}
Innovator.search(searchPhrase).searchResults
}
Now I can use findPersons('julius.caesar#domain.com') to find Person object. But this is exact value and I would like to use also prefix search for email field.
For example: findPersons('julius.caesar#doma') should also return Person as a result.
Thank you for any tips and any help in solving this issue.
Regards,
Kamil

how to prevent casade on updates

I'm working in grails and I've noticed some strange behavior to which I'd like to fix but I cannot figure out what I'm missing.
I have a location which can have may buildings. Each building can have multiple suites.
In addition I have a tenant who has a tenant location. The tenant location is used more for historical reporting so that we can see if tenants have moved locations.
The classes look like this
class Location {
String name
String shortName
Country country
LocationTypeEnum locationType = LocationTypeEnum.STUD // as default
static hasMany = [building: Building]
Date dateCreated
Date lastUpdated
static constraints = {
name unique: true, maxSize: 30
shortName unique: true, maxSize: 3
country nullable: false
locationType nullable: false
}
static mapping = {
cache usage: 'nonstrict-read-write', include: 'non-lazy'
}
}
class Building {
String type
String name
Date dateCreated
Date lastUpdated
static belongsTo = [location: Location]
static hasMany = [suites: Suite]
static constraints = {
name unique: true, maxSize: 25
type inList: ["A", "B", "C"], nullable: true
}
String toString() {
name
}
}
class Suite {
int suiteNumber
Date dateCreated
static belongsTo = [building: Building]
static constraints = {
pen(validator: { return it > 0 && (it.toString().length()) <= 3 })
}
String toString() {
suite.toString()
}
}
class Tenant {
static hasMany = [tenantLocation: TenantLocation]
----
Suite suite
String comments
Date dateCreated
Date lastUpdated
boolean active = true
static constraints = {
--------
type
nullable: false
comments maxSize: 5000
}
}
class TenantLocation {
static belongsTo = [tenant: Tenant]
Tenant tenant
Suite suite
Date dateCreated
}
So the idea is that a tenant location is created when tenant is created and a new tenantLocation is created only if and when the current tenant suite changes.
However, what I'm seeing is not only is the tenantLocation being saved (which is what I want) the suite is also being updated (which is not what I want).
For example I have Building 1 and suites 1 - 20 and Building 2 with suites 1 - 25. I have a tenant that is in Building 1 suite 5, they move to Building 2 suite 23. Now all of a sudden Building 2 has two suites with a suite number of 5.
How do I keep my suites from moving from one building to another when I only want the suite the tenant has to change?
The Code that is doing the updating is in the Tenant Controller and looks like this:
def update() {
def tenantInstance = Tenant.get(params.id)
if (!tenantInstance) {
flash.message = message(code: 'default.not.found.message', args: [
message(code: 'tenant.label', default: 'Tenant'),
params.id
])
redirect action: "list"
return
}
if (params.version) {
def version = params.version.toLong()
if (tenantInstance.version > version) {
tenantInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
[
message(code: 'tenantInstance.label', default: 'Tenant')] as Object[],
"Another user has updated this Tenant while you were editing")
render view: "edit", model: [tenantInstance: tenantInstance, BuidingListInstance: Building.list()]
return
}
}
tenantInstance.properties = params
if (!tenantInstance.save(flush: true)) {
render view: "edit", model: [tenantInstance: tenantInstance, BuildingListInstance: Building.list()]
return
}
def tenantLocation= TenantLocation.findAllByTenant(tenantInstance)
def locationCheck = tenantLocation.last()
//if tenant location is not null and the suite/building change create new Tenant Location entry
if (tenantLocation!=null)
{
if(locationCheck.pen.id !=tenantInstance.suite.id)
{
def location = new TenantLocation(
tenant: tenantInstance,
suite: tenantInstance.suite,
dateCreated: new Date()
).save(flush:true)
}
}
flash.message = message(code: 'default.updated.message', args: [
message(code: 'tenant.label', default: 'Tenant'),
tenantInstance.id
])
redirect action: "show", id: tenantInstance.id
}

Grails Integration test: Failure...Cannot invoke method addToPosts() on null object

:D
I was following a tutorial in a book, and I did follow it thoroughly.
However, come the part where I am supposed to write an integration test, it suddenly failed saying: Cannot invoke method addToPosts() on null object right after I ran the test. I wonder, what could be wrong... :| Please help! :) Below is the code for the test:
void testFirstPost() {
def user = new User(userID: 'joemillan', password:'youaretheonly',
homepage: 'www.geeee.com').save()
def post = new Post (content: 'hellloo oasdo sjdosa daodkao ')
user.addToPosts(post)
assertEquals 1, User.get(user.id).posts.size()
}
Here is the user class:
class User {
String userID
String password
String homepage
Profile profile
static hasMany=[posts:Post, tags:Tag]
static constraints = {
userID (unique: true, size: 6..20)
password (size: 6..20, validator:{password,userID-> return password !=userID.userID}) //validator = The password must not match the username.
homepage (url:true, nullable: true)
profile (nullable: true)
}
}
Here is the Post class:
class Post {
String content
Date dateCreated
static constraints = {
content (blank:false)
}
static belongsTo = [user:User]
static hasMany = [tags:Tag]
static mapping = {
sort dateCreated: "desc"
}
}
save() returns null if validation fails, and "www.geeee.com" isn't a valid URL. It would work with "http://www.geeee.com".
But you should split the creation and saving into 2 steps so you can check it:
def user = new User(userID: 'joemillan', password:'youaretheonly',
homepage: 'www.geeee.com')
user.save()
assertFalse user.hasErrors()
or use failOnError if you are confident that that part should succeed and only want to test the other parts, e.g.
def user = new User(userID: 'joemillan', password:'youaretheonly',
homepage: 'www.geeee.com').save(failOnError: true)

Resources