0
Groovy: Efficiency Oriented ProgrammingLecture 11Master Proteomics & Bioinformatics - University of GenevaAlexandre Massel...
Agenda‣ CRUD‣ Integration tests‣ Domain relationships‣ Application configuration
One domain based app ↔ one database
One domain class ↔ one table
One domain bean ↔ one table entry
One bean operations: CRUD
One bean operations: CRUD         Action        Create         Read        Update         Delete
One bean operations: CRUD         Action        Create         Read        Update         Delete
One bean operations: CRUD         Action        Create         Read        Update         Delete
One bean operations: CRUD         Action        Create         Read        Update         Delete
One bean operations: CRUD         Action       SQL    Grails url        Create      INSERT   create         Read       SEL...
One bean operations: CRUD         Action       SQL    Grails url        Create      INSERT   create         Read       SEL...
One bean operations: CRUD         Action       SQL    Grails url        Create      INSERT   create         Read       SEL...
Person joe = new Person(params)   ➙ bean but no database entry creation
joe.save()     ➙ insertion into table(only if valid bean - constraints)
Validation‣ Create only a valid bean‣ 3 validation ways
Validation‣ Create only a valid bean‣ 3 validation ways‣ Check explicitly for validation joe.validate()
Validation‣ Create only a valid bean‣ 3 validation ways‣ Check explicitly for validation joe.validate()‣ Save a catch exce...
Validation‣ Create only a valid bean‣ 3 validation ways‣ Check explicitly for validation joe.validate()‣ Save a catch exce...
Registered bean ⇔ joe.id != null
Reading a bean from the database
joe = Person.get(beanId)
Dynamic finders: retrieve from constraints
Dynamic finders (for single return)‣ Domain class definition generate static methods def p = Person.findByUsername(‘lucky_...
Dynamic finders (for single return)‣ Domain class definition generate static methods def p = Person.findByUsername(‘lucky_...
Dynamic finders (for single return)‣ Domain class definition generate static methods def p = Person.findByUsername(‘lucky_...
Update  ‣ Update: change fields values and save into database
Update  ‣ Update: change fields values and save into database  1. modify bean as usual
Update  ‣ Update: change fields values and save into database  1. modify bean as usual  2. validate/save as for creation
joe.delete() removes entry from table
Scaffolded controller hides CRUD operations
Explicit controller‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person
Explicit controller‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person‣ Per...
Explicit controller‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person‣ Per...
Time to go back to test!
Unit testing ↔ no dependency
Integration testing ↔ more complex biotope
Integration tests‣ Resides under test/integration/PersonIntegrationTests.groovy
Integration tests‣ Resides under test/integration/PersonIntegrationTests.groovy‣ Launched withtest-app -integration
Integration tests‣ Resides under test/integration/ PersonIntegrationTests.groovy‣ Launched with test-app -integration‣ Res...
Faster grails command‣ Launch command (<alt><ctrl>G) interactive
Faster grails command‣ Launch command (<alt><ctrl>G) interactive‣ On the console, enter commandtest-app -integration
Faster grails command‣ Launch command (<alt><ctrl>G) interactive‣ On the console, enter command test-app -integration‣ Hit...
Faster grails command‣ Launch command (<alt><ctrl>G) interactive‣ On the console, enter command test-app -integration‣ Hit...
Grails integration testing cons         ‣ Slower to execute than unit
Grails integration testing cons         ‣ Slower to execute than unit         ‣ Test report is not integrated into eclipse
Grails integration testing cons         ‣ Slower to execute than unit         ‣ Test report is not integrated into eclipse...
mockDomain: unit testing with domain class
mockDomain‣ It is possible to make some unit testing with domain
mockDomain‣ It is possible to make some unit testing with domain‣ No real database is connected, but a fake layer
mockDomain‣ It is possible to make some unit testing with domain‣ No real database is connected, but a fake layer‣ In each...
mockDomain‣ It is possible to make some unit testing with domain‣ No real database is connected, but a fake layer‣ In each...
mockDomain example void testDelete(){     //buildDaltonFamily() return a list of 4 Person  mockDomain(Person, buildDaltonF...
mockDomain limits‣ No explicit database operation (hibernate criteria, HQL) are  possible
mockDomain limits‣ No explicit database operation (hibernate criteria, HQL) are  possible‣ Multiple domain class interacti...
mockDomain limits‣ No explicit database operation (hibernate criteria, HQL) are  possible‣ Multiple domain class interacti...
Hermit domain not very useful
Need for relationshipsTwitter: Person ↔ Message
Message domaincreate-domain-class Domain
Message domaincreate-domain-class Domain‣ Just a text (String) and a commiter (Person)class Message {    String text    Pe...
Message + Person‣ Attach two messages to a user Person joe=Person.findByUsername(joe_dalton) new Message(text:hello, commi...
Message + Person‣ Attach two messages to a user Person joe=Person.findByUsername(joe_dalton) new Message(text:hello, commi...
Message + Person‣ Attach two messages to a user Person joe=Person.findByUsername(joe_dalton) new Message(text:hello, commi...
Define a one-to-many relationship
One-to-many relationship‣Message.groovy//Person commiterstatic belongsTo = [commiter:Person]
One-to-many relationship‣Message.groovy//Person commiterstatic belongsTo = [commiter:Person]‣Person.groovystatic hasMany =...
One-to-many relationship                        (cont’d)‣ Add a message:joe.addToMessages(new Message(text:‘hello world’))...
One-to-many relationship                         (cont’d)‣ Add a message: joe.addToMessages(new Message(text:‘hello world’...
One-to-many relationship   (cont’d)‣ Access to the list joe.messages
One-to-many relationship                                     (cont’d)‣ Access to the list joe.messages‣ Deleting will casc...
Testing‣ Test database consistency with two domain: integration testing     // taken from MessageIntegrationTests.groovy  ...
Back to the web: 2 scaffolded controllers
groovy & grails - lecture 11
groovy & grails - lecture 11
groovy & grails - lecture 11
groovy & grails - lecture 11
Upcoming SlideShare
Loading in...5
×

groovy & grails - lecture 11

453

Published on

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
453
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
20
Comments
0
Likes
1
Embeds 0
No embeds

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 &lt;-&gt; 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 =&gt; table index\n
  • possible to configure sort on other condition in domain class definition\nunique:true =&gt; table index\n
  • possible to configure sort on other condition in domain class definition\nunique:true =&gt; table index\n
  • if not valid =&gt; bean remains the same in the database\n
  • if not valid =&gt; bean remains the same in the database\n
  • if not valid =&gt; 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 of "groovy & grails - lecture 11"

    1. 1. Groovy: Efficiency Oriented ProgrammingLecture 11Master Proteomics & Bioinformatics - University of GenevaAlexandre Masselot - summer 2011
    2. 2. Agenda‣ CRUD‣ Integration tests‣ Domain relationships‣ Application configuration
    3. 3. One domain based app ↔ one database
    4. 4. One domain class ↔ one table
    5. 5. One domain bean ↔ one table entry
    6. 6. One bean operations: CRUD
    7. 7. One bean operations: CRUD Action Create Read Update Delete
    8. 8. One bean operations: CRUD Action Create Read Update Delete
    9. 9. One bean operations: CRUD Action Create Read Update Delete
    10. 10. One bean operations: CRUD Action Create Read Update Delete
    11. 11. One bean operations: CRUD Action SQL Grails url Create INSERT create Read SELECT show Update UPDATE update Delete DELETE delete
    12. 12. One bean operations: CRUD Action SQL Grails url Create INSERT create Read SELECT show Update UPDATE update Delete DELETE delete
    13. 13. One bean operations: CRUD Action SQL Grails url Create INSERT create Read SELECT show Update UPDATE update Delete DELETE delete
    14. 14. Person joe = new Person(params) ➙ bean but no database entry creation
    15. 15. joe.save() ➙ insertion into table(only if valid bean - constraints)
    16. 16. Validation‣ Create only a valid bean‣ 3 validation ways
    17. 17. Validation‣ Create only a valid bean‣ 3 validation ways‣ Check explicitly for validation joe.validate()
    18. 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. 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. 20. Registered bean ⇔ joe.id != null
    21. 21. Reading a bean from the database
    22. 22. joe = Person.get(beanId)
    23. 23. Dynamic finders: retrieve from constraints
    24. 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. 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. 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. 27. Update ‣ Update: change fields values and save into database
    28. 28. Update ‣ Update: change fields values and save into database 1. modify bean as usual
    29. 29. Update ‣ Update: change fields values and save into database 1. modify bean as usual 2. validate/save as for creation
    30. 30. joe.delete() removes entry from table
    31. 31. Scaffolded controller hides CRUD operations
    32. 32. Explicit controller‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person
    33. 33. Explicit controller‣ It is possible to generate scaffold controller code generate-controller eop.lec11.twitter.Person‣ PersonController.groovy write operation & test
    34. 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. 35. Time to go back to test!
    36. 36. Unit testing ↔ no dependency
    37. 37. Integration testing ↔ more complex biotope
    38. 38. Integration tests‣ Resides under test/integration/PersonIntegrationTests.groovy
    39. 39. Integration tests‣ Resides under test/integration/PersonIntegrationTests.groovy‣ Launched withtest-app -integration
    40. 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. 41. Faster grails command‣ Launch command (<alt><ctrl>G) interactive
    42. 42. Faster grails command‣ Launch command (<alt><ctrl>G) interactive‣ On the console, enter commandtest-app -integration
    43. 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. 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. 45. Grails integration testing cons ‣ Slower to execute than unit
    46. 46. Grails integration testing cons ‣ Slower to execute than unit ‣ Test report is not integrated into eclipse
    47. 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. 48. mockDomain: unit testing with domain class
    49. 49. mockDomain‣ It is possible to make some unit testing with domain
    50. 50. mockDomain‣ It is possible to make some unit testing with domain‣ No real database is connected, but a fake layer
    51. 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. 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. 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. 54. mockDomain limits‣ No explicit database operation (hibernate criteria, HQL) are possible
    55. 55. mockDomain limits‣ No explicit database operation (hibernate criteria, HQL) are possible‣ Multiple domain class interaction are fully possible (cf. relationships)
    56. 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. 57. Hermit domain not very useful
    58. 58. Need for relationshipsTwitter: Person ↔ Message
    59. 59. Message domaincreate-domain-class Domain
    60. 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. 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. 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. 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. 64. Define a one-to-many relationship
    65. 65. One-to-many relationship‣Message.groovy//Person commiterstatic belongsTo = [commiter:Person]
    66. 66. One-to-many relationship‣Message.groovy//Person commiterstatic belongsTo = [commiter:Person]‣Person.groovystatic hasMany = [messages: Message]
    67. 67. One-to-many relationship (cont’d)‣ Add a message:joe.addToMessages(new Message(text:‘hello world’)).save()
    68. 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. 69. One-to-many relationship (cont’d)‣ Access to the list joe.messages
    70. 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. 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. 72. Back to the web: 2 scaffolded controllers
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×