Your SlideShare is downloading. ×
groovy & grails - lecture 11
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

groovy & grails - lecture 11

409
views

Published on

CRUD …

CRUD
Integration tests
Domain relationships
Application configuration

Published in: Technology, Education

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
409
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
16
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • \n
  • \n
  • \n
  • run-app generate the database\n
  • Domain bean class generate a table from the member fields\n
  • map one object <-> SQL statements\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • id property is added by default to domain beans\nsetting the bean joe.id=123 is dangerous\n
  • \n
  • necessitate to know the beanId value\ntypically used with url show/id\n
  • \n
  • possible to configure sort on other condition in domain class definition\nunique:true => table index\n
  • possible to configure sort on other condition in domain class definition\nunique:true => table index\n
  • possible to configure sort on other condition in domain class definition\nunique:true => table index\n
  • if not valid => bean remains the same in the database\n
  • if not valid => bean remains the same in the database\n
  • if not valid => bean remains the same in the database\n
  • \n
  • \n
  • do not call generate-controller too early in development phase\n
  • do not call generate-controller too early in development phase\n
  • do not call generate-controller too early in development phase\n
  • \n
  • \n
  • database\nsame situation ~ than with run-app\n
  • PersonIntegrationTests instead PersonTests to avoid class name conflict\n
  • PersonIntegrationTests instead PersonTests to avoid class name conflict\n
  • PersonIntegrationTests instead PersonTests to avoid class name conflict\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • see error groovy 1.6 on the storyboard\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • This is not the correct way!\n
  • This is not the correct way!\n
  • \n
  • \n
  • \n
  • grails will provide the mechanism for consistency\n
  • \n
  • \n
  • addToMessages is implicitely created\n
  • addToMessages is implicitely created\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Transcript

    • 1. Groovy: Efficiency Oriented ProgrammingLecture 11Master Proteomics & Bioinformatics - University of GenevaAlexandre Masselot - summer 2011
    • 2. Agenda‣ CRUD‣ Integration tests‣ Domain relationships‣ Application configuration
    • 3. One domain based app ↔ one database
    • 4. One domain class ↔ one table
    • 5. One domain bean ↔ one table entry
    • 6. One bean operations: CRUD
    • 7. One bean operations: CRUD Action Create Read Update Delete
    • 8. One bean operations: CRUD Action Create Read Update Delete
    • 9. One bean operations: CRUD Action Create Read Update Delete
    • 10. One bean operations: CRUD Action Create Read Update Delete
    • 11. One bean operations: CRUD Action SQL Grails url Create INSERT create Read SELECT show Update UPDATE update Delete DELETE delete
    • 12. One bean operations: CRUD Action SQL Grails url Create INSERT create Read SELECT show Update UPDATE update Delete DELETE delete
    • 13. One bean operations: CRUD Action SQL Grails url Create INSERT create Read SELECT show Update UPDATE update Delete DELETE delete
    • 14. Person joe = new Person(params) ➙ bean but no database entry creation
    • 15. joe.save() ➙ insertion into table(only if valid bean - constraints)
    • 16. Validation‣ Create only a valid bean‣ 3 validation ways
    • 17. Validation‣ Create only a valid bean‣ 3 validation ways‣ Check explicitly for validation joe.validate()
    • 18. Validation‣ Create only a valid bean‣ 3 validation ways‣ Check explicitly for validation joe.validate()‣ Save a catch exception joe.save(failOnError:true)
    • 19. Validation‣ Create only a valid bean‣ 3 validation ways‣ Check explicitly for validation joe.validate()‣ Save a catch exception joe.save(failOnError:true)‣ Save a check for non-null return assert joe.save()
    • 20. Registered bean ⇔ joe.id != null
    • 21. Reading a bean from the database
    • 22. joe = Person.get(beanId)
    • 23. Dynamic finders: retrieve from constraints
    • 24. Dynamic finders (for single return)‣ Domain class definition generate static methods def p = Person.findByUsername(‘lucky_luke’) def p = Person.findByFirstName(‘Lucky’) def p = Person.findByFirstNameAndLastName(‘Joe’, ‘Dalton’)
    • 25. Dynamic finders (for single return)‣ Domain class definition generate static methods def p = Person.findByUsername(‘lucky_luke’) def p = Person.findByFirstName(‘Lucky’) def p = Person.findByFirstNameAndLastName(‘Joe’, ‘Dalton’)‣ Multiple results => returns first (sorted on id) def p = Person.findByLastName(‘Dalton’)
    • 26. Dynamic finders (for single return)‣ Domain class definition generate static methods def p = Person.findByUsername(‘lucky_luke’) def p = Person.findByFirstName(‘Lucky’) def p = Person.findByFirstNameAndLastName(‘Joe’, ‘Dalton’)‣ Multiple results => returns first (sorted on id) def p = Person.findByLastName(‘Dalton’)‣ findByXxxx efficient with unique:true fields
    • 27. Update ‣ Update: change fields values and save into database
    • 28. Update ‣ Update: change fields values and save into database 1. modify bean as usual
    • 29. Update ‣ Update: change fields values and save into database 1. modify bean as usual 2. validate/save as for creation
    • 30. joe.delete() removes entry from table
    • 31. Scaffolded controller hides CRUD operations
    • 32. Explicit controller‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person
    • 33. Explicit controller‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person‣ PersonController.groovy write operation & test
    • 34. Explicit controller‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person‣ PersonController.groovy write operation & test‣ For example, read: def show = { def personInstance = Person.get(params.id) if (!personInstance) { flash.message = "${message(code: default.not.found.message, .....)}" redirect(action: "list") } else { [personInstance: personInstance] } }
    • 35. Time to go back to test!
    • 36. Unit testing ↔ no dependency
    • 37. Integration testing ↔ more complex biotope
    • 38. Integration tests‣ Resides under test/integration/PersonIntegrationTests.groovy
    • 39. Integration tests‣ Resides under test/integration/PersonIntegrationTests.groovy‣ Launched withtest-app -integration
    • 40. Integration tests‣ Resides under test/integration/ PersonIntegrationTests.groovy‣ Launched with test-app -integration‣ Results: - summary on the console output (count success/failures) - html files under target/tests-reports/html - plain text files under target/tests-reports/html - failure summary available - stdout/stderr accessible for each test case
    • 41. Faster grails command‣ Launch command (<alt><ctrl>G) interactive
    • 42. Faster grails command‣ Launch command (<alt><ctrl>G) interactive‣ On the console, enter commandtest-app -integration
    • 43. Faster grails command‣ Launch command (<alt><ctrl>G) interactive‣ On the console, enter command test-app -integration‣ Hit enter to relaunch last command
    • 44. Faster grails command‣ Launch command (<alt><ctrl>G) interactive‣ On the console, enter command test-app -integration‣ Hit enter to relaunch last command‣ After several commands, PermGenException can occur - terminate - relaunch interactive
    • 45. Grails integration testing cons ‣ Slower to execute than unit
    • 46. Grails integration testing cons ‣ Slower to execute than unit ‣ Test report is not integrated into eclipse
    • 47. Grails integration testing cons ‣ Slower to execute than unit ‣ Test report is not integrated into eclipse ‣ Use only when unit test not possible
    • 48. mockDomain: unit testing with domain class
    • 49. mockDomain‣ It is possible to make some unit testing with domain
    • 50. mockDomain‣ It is possible to make some unit testing with domain‣ No real database is connected, but a fake layer
    • 51. mockDomain‣ It is possible to make some unit testing with domain‣ No real database is connected, but a fake layer‣ In each method (not setup()) mockDomain(Person) mockDomain(Person, initialBeanList)
    • 52. mockDomain‣ It is possible to make some unit testing with domain‣ No real database is connected, but a fake layer‣ In each method (not setup()) mockDomain(Person) mockDomain(Person, initialBeanList)‣ All single domain CRUD (and more) operations possible
    • 53. mockDomain example void testDelete(){ //buildDaltonFamily() return a list of 4 Person mockDomain(Person, buildDaltonFamily()) assert Person.count() == 4 Person p=Person.findByUsername(joe_dalton) assertNotNull p p.delete() // we should only have 3 members left assert Person.count() == 3 p=Person.findByUsername(joe_dalton) assertNull p }
    • 54. mockDomain limits‣ No explicit database operation (hibernate criteria, HQL) are possible
    • 55. mockDomain limits‣ No explicit database operation (hibernate criteria, HQL) are possible‣ Multiple domain class interaction are fully possible (cf. relationships)
    • 56. mockDomain limits‣ No explicit database operation (hibernate criteria, HQL) are possible‣ Multiple domain class interaction are fully possible (cf. relationships)‣ Connection with data already entered in a database
    • 57. Hermit domain not very useful
    • 58. Need for relationshipsTwitter: Person ↔ Message
    • 59. Message domaincreate-domain-class Domain
    • 60. Message domaincreate-domain-class Domain‣ Just a text (String) and a commiter (Person)class Message { String text Person commiter static constraints = { text(size:1..140, blank:false) commiter(nullable:false) }}
    • 61. Message + Person‣ Attach two messages to a user Person joe=Person.findByUsername(joe_dalton) new Message(text:hello, commiter:joe).save() new Message(text:world, commiter:joe).save()
    • 62. Message + Person‣ Attach two messages to a user Person joe=Person.findByUsername(joe_dalton) new Message(text:hello, commiter:joe).save() new Message(text:world, commiter:joe).save()‣ Look for message from joe Message.findAllByCommiter(joe)
    • 63. Message + Person‣ Attach two messages to a user Person joe=Person.findByUsername(joe_dalton) new Message(text:hello, commiter:joe).save() new Message(text:world, commiter:joe).save()‣ Look for message from joe Message.findAllByCommiter(joe)‣ Not possible to access to message directly from joe bean - one solution: explicitly declare setCommiter(Person p) in Message.groovy that would add the message to a list in joe; - problem for deletion, save inconsistency...
    • 64. Define a one-to-many relationship
    • 65. One-to-many relationship‣Message.groovy//Person commiterstatic belongsTo = [commiter:Person]
    • 66. One-to-many relationship‣Message.groovy//Person commiterstatic belongsTo = [commiter:Person]‣Person.groovystatic hasMany = [messages: Message]
    • 67. One-to-many relationship (cont’d)‣ Add a message:joe.addToMessages(new Message(text:‘hello world’)).save()
    • 68. One-to-many relationship (cont’d)‣ Add a message: joe.addToMessages(new Message(text:‘hello world’)).save()‣ Will execute the following actions - create a message with joe as commiter - save the message - add the message to joe’s list
    • 69. One-to-many relationship (cont’d)‣ Access to the list joe.messages
    • 70. One-to-many relationship (cont’d)‣ Access to the list joe.messages‣ Deleting will cascade joe.delete() - all messages with joe as commiter will also be deleted
    • 71. Testing‣ Test database consistency with two domain: integration testing // taken from MessageIntegrationTests.groovy // 4 Person are added in the setup() method public void testListMessagesUserDeletion(){ Person joe=Person.findByUsername(joe_dalton) Person averell=Person.findByUsername(averell_dalton) joe.addToMessages(new Message(text:hello world)).save() joe.addToMessages(new Message(text:im running)).save() averell.addToMessages(new Message(text:im eating)).save() assert Message.count() == 3 assert Person.count() == 4 joe.delete() assert Person.count() == 3 //having deleted joe should delete all message related to joe assert Message.count() == 1 }
    • 72. Back to the web: 2 scaffolded controllers

    ×