Groovier Selenium (Djug)

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    3 Favorites

    Groovier Selenium (Djug) - Presentation Transcript

    1. Groovier Selenium Denver JUG 8/13/2008 Frederic Jean fred@fredjean.net frederic.jean@sun.com Wednesday, August 13, 2008 1
    2. who am i Wednesday, August 13, 2008 2
    3. Topics (Really) Quick intro to Selenium Groovy Metaprogramming through progressive refactorings of a single, simple yet verbose Java Selenium RC Driver example. A few sundry items Wednesday, August 13, 2008 3
    4. Selenium UI testing tool Runs in browser Well suited for Ajax applications Wednesday, August 13, 2008 4
    5. Selenium IDE Firefox plugin Simplifies writing and testing Selenese test case Can record and play back Selenese tests Wednesday, August 13, 2008 5
    6. Selenese HTML Tables Action Target Value Intepreted by Selenium Core Actions match JavaScript functions Wednesday, August 13, 2008 6
    7. Example BlogTest open / clickAndWait link=Adoption Out of my mind... : category assertTitle adoption Wednesday, August 13, 2008 7
    8. Selenese Locators Allows an action to target a specific DOM element on the page <type>=<locator> Wednesday, August 13, 2008 8
    9. Selenese Locators Locator Type Description The name of an input element on a name form The id associated with an element id on a page The text contained within an anchor link element (<a/>) A JavaScript expression that dom returns an element An XPath expression pointing to an xpath element on the page Wednesday, August 13, 2008 9
    10. Sample Test Wednesday, August 13, 2008 10
    11. Selenese TestSuites Groups and organizes individual Selenese tests Can be run through ant Wednesday, August 13, 2008 11
    12. Selenium RC Runs as a process on a system Listens to requests on a specific port Has drivers for different languages Wednesday, August 13, 2008 12
    13. Selenium RC Drivers Drives the Selenium RC Ser ver programatically Allows integration with xUnit frameworks Flow control and conditionals Java driver provides a SeleneseTestCase class Wednesday, August 13, 2008 13
    14. Generating Java Test Wednesday, August 13, 2008 14
    15. Generated Java package com.example.tests; import com.thoughtworks.selenium.*; import java.util.regex.Pattern; public class NewTest extends SeleneseTestCase { public void setUp() throws Exception { setUp(\"http://fredjean.net/\", \"*chrome\"); } public void testNew() throws Exception { selenium.open(\"/\"); selenium.click(\"link=Adoption\"); selenium.waitForPageToLoad(\"30000\"); assertEquals(\"Out of my mind... : category adoption\", selenium.getTitle()); selenium.click(\"link=We Are Out!\"); for (int second = 0;; second++) { if (second >= 60) fail(\"timeout\"); try { if (selenium.isTextPresent(\"Comments\")) break; } catch (Exception e) {} Thread.sleep(1000); } assertTrue(selenium.isTextPresent(\"Trackbacks\")); } } Wednesday, August 13, 2008 15
    16. Generated Java Where package com.example.tests; import com.thoughtworks.selenium.*; is it used? import java.util.regex.Pattern; public class NewTest extends SeleneseTestCase { public void setUp() throws Exception { setUp(\"http://fredjean.net/\", \"*chrome\"); } public void testNew() throws Exception { selenium.open(\"/\"); selenium.click(\"link=Adoption\"); selenium.waitForPageToLoad(\"30000\"); assertEquals(\"Out of my mind... : category adoption\", selenium.getTitle()); selenium.click(\"link=We Are Out!\"); for (int second = 0;; second++) { if (second >= 60) fail(\"timeout\"); try { if (selenium.isTextPresent(\"Comments\")) break; } catch (Exception e) {} Thread.sleep(1000); } assertTrue(selenium.isTextPresent(\"Trackbacks\")); } } Wednesday, August 13, 2008 16
    17. Generated Java package com.example.tests; import com.thoughtworks.selenium.*; Need to rename class. import java.util.regex.Pattern; public class NewTest extends SeleneseTestCase { public void setUp() throws Exception { setUp(\"http://fredjean.net/\", \"*chrome\"); } public void testNew() throws Exception { selenium.open(\"/\"); selenium.click(\"link=Adoption\"); selenium.waitForPageToLoad(\"30000\"); assertEquals(\"Out of my mind... : category adoption\", selenium.getTitle()); selenium.click(\"link=We Are Out!\"); for (int second = 0;; second++) { if (second >= 60) fail(\"timeout\"); try { if (selenium.isTextPresent(\"Comments\")) break; } catch (Exception e) {} Thread.sleep(1000); } assertTrue(selenium.isTextPresent(\"Trackbacks\")); } } Wednesday, August 13, 2008 17
    18. Generated Java from Must inherit SeleneseTestCase package com.example.tests; import com.thoughtworks.selenium.*; import java.util.regex.Pattern; public class NewTest extends SeleneseTestCase { public void setUp() throws Exception { setUp(\"http://fredjean.net/\", \"*chrome\"); } public void testNew() throws Exception { selenium.open(\"/\"); selenium.click(\"link=Adoption\"); selenium.waitForPageToLoad(\"30000\"); assertEquals(\"Out of my mind... : category adoption\", selenium.getTitle()); selenium.click(\"link=We Are Out!\"); for (int second = 0;; second++) { if (second >= 60) fail(\"timeout\"); try { if (selenium.isTextPresent(\"Comments\")) break; } catch (Exception e) {} Thread.sleep(1000); } assertTrue(selenium.isTextPresent(\"Trackbacks\")); } } Wednesday, August 13, 2008 18
    19. Generated Java package com.example.tests; import com.thoughtworks.selenium.*; import java.util.regex.Pattern; Should rename method public class NewTest extends SeleneseTestCase { public void setUp() throws Exception { setUp(\"http://fredjean.net/\", \"*chrome\"); } public void testNew() throws Exception { selenium.open(\"/\"); selenium.click(\"link=Adoption\"); selenium.waitForPageToLoad(\"30000\"); assertEquals(\"Out of my mind... : category adoption\", selenium.getTitle()); selenium.click(\"link=We Are Out!\"); for (int second = 0;; second++) { if (second >= 60) fail(\"timeout\"); try { if (selenium.isTextPresent(\"Comments\")) break; } catch (Exception e) {} Thread.sleep(1000); } assertTrue(selenium.isTextPresent(\"Trackbacks\")); } } Wednesday, August 13, 2008 19
    20. Generated Java package com.example.tests; selenium.this import com.thoughtworks.selenium.*; import java.util.regex.Pattern; selenium.that public class NewTest extends SeleneseTestCase { public void setUp() throws Exception { } selenium.thisandthat setUp(\"http://fredjean.net/\", \"*chrome\"); public void testNew() throws Exception { selenium.open(\"/\"); selenium.click(\"link=Adoption\"); selenium.waitForPageToLoad(\"30000\"); assertEquals(\"Out of my mind... : category adoption\", selenium.getTitle()); selenium.click(\"link=We Are Out!\"); for (int second = 0;; second++) { if (second >= 60) fail(\"timeout\"); try { if (selenium.isTextPresent(\"Comments\")) break; } catch (Exception e) {} Thread.sleep(1000); } assertTrue(selenium.isTextPresent(\"Trackbacks\")); } } Wednesday, August 13, 2008 20
    21. Generated Java package com.example.tests; import com.thoughtworks.selenium.*; import java.util.regex.Pattern; public class NewTest extends SeleneseTestCase { public void setUp() throws Exception { setUp(\"http://fredjean.net/\", \"*chrome\"); } public void testNew() throws Exception { Where did waitForTextPresent go? selenium.open(\"/\"); selenium.click(\"link=Adoption\"); selenium.waitForPageToLoad(\"30000\"); assertEquals(\"Out of my mind... : category adoption\", selenium.getTitle()); selenium.click(\"link=We Are Out!\"); for (int second = 0;; second++) { if (second >= 60) fail(\"timeout\"); try { if (selenium.isTextPresent(\"Comments\")) break; } catch (Exception e) {} Thread.sleep(1000); } assertTrue(selenium.isTextPresent(\"Trackbacks\")); } } Wednesday, August 13, 2008 21
    22. Generated Java Good start Needs some work to be useful Certainly faster than coding by hand Noisy Wednesday, August 13, 2008 22
    23. Groovy package com.example.tests import com.thoughtworks.selenium.* class NewGroovyTest extends SeleneseTestCase { void setUp() { setUp \"http://fredjean.net/\", \"*chrome\" } void testNew() { selenium.open \"/\" selenium.click \"link=Adoption\" selenium.waitForPageToLoad \"30000\" assert \"Out of my mind... : category adoption\" == selenium.title selenium.click \"link=We Are Out!\" for (second in 0..60) { if (second == 60) fail \"timeout\" if (selenium.isTextPresent(\"Comments\")) break; sleep(1000) } assert selenium.isTextPresent(\"Trackbacks\") } } Wednesday, August 13, 2008 23
    24. Groovy Less noisy than Java Still repetitive waitForTextPresent is still missing Wednesday, August 13, 2008 24
    25. Metaprogramming Writing of computer programs that write or manipulate other programs (or themselves) as their data. http://en.wikipedia.org/wiki/Metaprogramming Wednesday, August 13, 2008 25
    26. Metaprogramming Increases code expressiveness Allows SMEs to understand the code Domain Specific Languages Wednesday, August 13, 2008 26
    27. Meta Object Protocol Establishes the rules behind method calling in Groovy Provides the hooks to modify your program's behavior invokeMethod propertyMissing methodMissing Wednesday, August 13, 2008 27
    28. Metaclass All Groovy objects have one Can be defined for Java objects Per class vs per instance Allows developers to \"mutate\" a class Wednesday, August 13, 2008 28
    29. Delegation For ward method calls to another object Tedious to do in Java Extend delegate Manually code delegation code Almost trivial in Groovy ExpandoMetaClass Wednesday, August 13, 2008 29
    30. Groovy Delegation /** * Called when a method cannot be found in the class * or the meta class for an object or class. * @param name The name of the missing method * @param args The arguments for the method */ void methodMissing(String name, args) { selenium.\"$name\"(* args) } /** * Called when a property cannot be found in the class * or the meta class associated with a class or object. * @param name The name of the property */ void propertyMissing(String name) { selenium.\"$name\" } Wednesday, August 13, 2008 30
    31. Goodbye Repetition void testDelegation() { open \"/\" click \"link=Adoption\" waitForPageToLoad \"30000\" assert \"Out of my mind... : category adoption\" == title click \"link=We Are Out!\" for (second in 0..60) { if (second == 60) fail \"timeout\" if (isTextPresent(\"Comments\")) break; sleep(1000) } assert isTextPresent(\"Trackbacks\") } Wednesday, August 13, 2008 31
    32. Performance Hit Wednesday, August 13, 2008 32
    33. Performance Hit Wednesday, August 13, 2008 33
    34. Intercept, Cache, Invoke /** * Called when a method cannot be found in the class * or the meta class for an object or class. * @param name The name of the missing method * @param args The arguments for the method */ void methodMissing(String name, args) { NewGroovyTest.metaClass.\"$name\" = { Object varArgs -> delegate.selenium.metaClass.invokeMethod(delegate.selenium, name, varArgs) } selenium.\"$name\"(* args) } Wednesday, August 13, 2008 34
    35. Performance Hit Wednesday, August 13, 2008 35
    36. Groovy Delegation Results in cleaner test code Almost trivial to implement in Groovy Performance hit can be mitigated Wednesday, August 13, 2008 36
    37. waitForTextPresent? void testDelegation() { open \"/\" click \"link=Adoption\" waitForPageToLoad \"30000\" assert \"Out of my mind... : category adoption\" == title click \"link=We Are Out!\" for (second in 0..60) { if (second == 60) fail \"timeout\" if (isTextPresent(\"Comments\")) break; sleep(1000) } assert isTextPresent(\"Trackbacks\") } Wednesday, August 13, 2008 37
    38. waitForTextPresent? void testDelegation() { open \"/\" Replaces waitFor... click \"link=Adoption\" waitForPageToLoad \"30000\" with a loop assert \"Out of my mind... : category adoption\" == title click \"link=We Are Out!\" for (second in 0..60) { if (second == 60) fail \"timeout\" if (isTextPresent(\"Comments\")) break; sleep(1000) } assert isTextPresent(\"Trackbacks\") } Wednesday, August 13, 2008 38
    39. waitForTextPresent? void testDelegation() { open \"/\" click \"link=Adoption\" waitForPageToLoad \"30000\" assert \"Out of my mind... : category adoption\" == title click \"link=We Are Out!\" for (second in 0..60) { How about if (second == 60) fail \"timeout\" assertTextPresent? if (isTextPresent(\"Comments\")) break; sleep(1000) } assert isTextPresent(\"Trackbacks\") } Wednesday, August 13, 2008 39
    40. waitForTextPresent? Selenese generates waitFor, verify, and assert methods Java driver doesn't provide them Java -> Explicitly typed language JavaScript -> What's a type? Wednesday, August 13, 2008 40
    41. Wait a minute... JavaScript is a dynamic language... Groovy is a dynamic language... Why not synthesize these methods in Groovy? Wednesday, August 13, 2008 41
    42. Synthetic Methods Methods that don't really exist Grails finder methods Person.findByFirstNameAndAge(...) Wednesday, August 13, 2008 42
    43. Steps to Take Identify synthetic methods Implement behavior Locate actual getter method Wednesday, August 13, 2008 43
    44. Identifying Methods def methodMissing(String name, args) { switch (name) { case ~/waitForNot.*/: return waitForNot(name, args) case ~/waitFor.*/: return waitFor(name, args) case ~/assertNot.*/: assertNot(name, args) break case ~/assert.*/: assertThat(name, args) break case ~/verifyNot.*/: return verifyNot(name, args) case ~/verify.*/: return verifyThat(name, args) default: return createAndCallMethod(name, args) } } Wednesday, August 13, 2008 44
    45. Implement Behavior private waitFor(name, args) { // Make the bold assumption that the time out is the first param. def timeout = args[0] if (timeout instanceof Integer) { args = args[1..args.length - 1].toArray() } else { timeout = 60000 } def methodName = getMethodName(\"waitFor\", name); for (i in 0..(timeout / 1000)) { if (\"$methodName\"(* args)) { return true; } sleep(1000) } fail(\"Timeout occured in $name for $args\") } Wednesday, August 13, 2008 45
    46. Locating Getter def getMethodName(prefix, name) { [\"is\", \"get\"].collect { name.replaceFirst(prefix, it) }.find { delegate.selenium.metaClass.respondsTo(delegate.selenium, it) } } Wednesday, August 13, 2008 46
    47. Loop Begone! void testDelegation() { open \"/\" click \"link=Adoption\" waitForPageToLoad \"30000\" assert \"Out of my mind... : category adoption\" == title click \"link=We Are Out!\" waitForTextPresent \"Comments\" assertTextPresent \"Trackbacks\" } Wednesday, August 13, 2008 47
    48. Refactor! Move methods to super class methodMissing propertyMissing Supporting methods Group Groovy tests in one suite Wednesday, August 13, 2008 48
    49. GroovierSelenium Extends SeleneseTestCase with methodMissing Allows Groovy users to write tests that almost look like Selenese http://groovierselenium.googlecode.com Licensed under ASLv2.0 Wednesday, August 13, 2008 49
    50. Near Future JUnit 4.5 test runners GroovierSeleniumRunner GroovySuiteRunner @Selenium annotation Wednesday, August 13, 2008 50
    51. NetBeans & Groovy Grails and Groovy Plugin integrated with NetBeans 6.5 Adds Groovy Support to Java Projects Wednesday, August 13, 2008 51
    52. Looking Back Talked about Selenium Leveraging Groovy metaprogramming Delegating to another object Creating synthetic methods GroovierSelenium NetBeans Wednesday, August 13, 2008 52
    53. Book Programming Groovy (Venkat S.) Wednesday, August 13, 2008 53
    54. Links http://groovy.codehaus.org http://groovierselenium.googlecode.com http://www.pragprog.com/titles/vslg/ programming-groovy Wednesday, August 13, 2008 54

    + fredjeanfredjean, 11 months ago

    custom

    1367 views, 3 favs, 3 embeds more stats

    Presentation on using Groovy's metaprogramming capa more

    More info about this document

    CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

    Go to text version

    • Total Views 1367
      • 1058 on SlideShare
      • 309 from embeds
    • Comments 0
    • Favorites 3
    • Downloads 69
    Most viewed embeds
    • 290 views on http://blog.fredjean.net
    • 18 views on http://fredjean.net
    • 1 views on http://www.agglom.com

    more

    All embeds
    • 290 views on http://blog.fredjean.net
    • 18 views on http://fredjean.net
    • 1 views on http://www.agglom.com

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories