groovy & grails - lecture 11

524
-1

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
524
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 <-> 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
  • 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.

    ×