Fluent
Lenium
Another way of using Selenium in
Java
Mathilde Lemée
Terracotta QA Engineer
DuchessFR Founder
Mobile dev – Aetys.fr
Java developper
FluentLenium
GREAT
tool
Ruby
APIS
Python
Java
.NET
Perl
PHP
GEB
WebDriver
Groovy
Jquery
Page object
Browser.drive {
go "http://google.com/ncr"
assert title == "Google”
$("input", name: "q").value("wikipedia”)
waitFor { tit...
Capybara
Ruby
Selenium
Webkit
Ruby drivers
Automatically waits
def login!
within("//form[@id='session']") do
fill_in 'Login', :with =>
'user@example.com'
fill_in 'Password', :with => 'p...
Java
Javascript
jQuery
CSS
Fluent
Lenium
find(“a”)
find(“#id”)
find(“.myClass”)
TARGET
find(".small",
withName("foo"))
FILTER
find(".small",
withClass("foo"))
FILTER
find(".small",
withId("foo"))
FILTER
find(".small",
withText("foo"))
FILTER
find(".small",
withAttribute(”at”)
.equalTo(”foo”))
FILTER
find(".small", withId().
contains(”foo”))
FILTER
find(".small", withId().
containsWord(”foo”))
FILTER
find(".small", withId().
startsWith(”foo”))
FILTER
find(".small", withId().
endsWith(”foo”))
FILTER
find(".small",
withId().contains(
Pattern.compile
("abc*")))
FILTER
find(".small", withName("foo"))
find(".small” ).first()
FINDfind(".small")
find(".small", withName().
startsWith(”my")
ACCESS
find(".small").getNames()
ACCESS
find(".small").getIds()
ACCESS
find(".small").getValues()
ACCESS
find(".small").getTexts()
ACCESS
find(".small").
getAttributes(”custom")
ACCESS
find(".small").
getText()
ACCESS
find(".small").
html()
ACTIONS
goTo(“http://www.google.fr”)
click("#create-button")
doubleClick("#create-button")
FILL
fill("input").with("m
yLogin","myPassw
ord")
fill("#name").with("Mathilde")
find("#name").text("Mathilde")
fill("inpu...
FORM
submit(“#myForm”)
clear("#myForm")
fill(“#name”).with(“Mathilde”)
ASSERTIONS
Your own
assertThat(title()).contains("Hello ");
assertThat(find(myCssSelecto2)).ha
sSize().lessThan(5);
public class BingTest extends FluentTest {
@Test
public void title_should_contain_query() {
goTo("http://www.bing.com");
f...
PAGE
OBJECT
PATTERN
Why ?
Readable
Maintenable
Separate
concerns
How?
No assertions
Services
Hide internals
of the page
FluentPage
isAt
methods
getUrl
public class LoginPage extends FluentPage {
public String getUrl() {
return "myCustomUrl";
}
public void isAt() {
assertTh...
@Page
LoginPage loginPage;
public void checkLoginFailed() {
goTo(loginPage);
loginPage.
fillAndSubmitLoginForm("login", ”w...
public class LoginPage extends FluentPage {
FluentWebElement createButton;
public String getUrl() {
return "myCustomUrl";
...
AWAIT
withDefaultSearchWait(long l, TimeUnit
timeUnit);
withDefaultPageWait(long l, TimeUnit
timeUnit);
isPresent()
await().
atMost(5,SECONDS).
until(".small").
await().
atMost(5,SECONDS).
until(".small").
hasName("name");
await().
atMost(5,SECONDS).
until(".small").
hasText(”text");
await().
atMost(5,SECONDS).
until(".small").containsText(”txt");
await().
atMost(5,SECONDS).
until(".small").
hasId("id");
await().
atMost(5,SECONDS).
until(".small").
hasSize(3);
await().
atMost(5,SECONDS).
until(".small").
hasSize().
greatherThan(3);
await().
atMost(5,SECONDS).
until(".small").
withText("myText").areDis
played();
await().
atMost(5,SECONDS).
until(".small").
withId("#id").
areEnabled();
await().
atMost(5,SECONDS).
until(".small").
with(”attribute").
startsWith(”xyz")
isPresent();
await().
atMost(5,SECONDS).
untilPage()
isLoaded();
await().
atMost(5,SECONDS).
untilPage()
isLoaded();
public class LoginPage extends
FluentPage {
@AjaxElement
FluentWebElement ajaxElem;
}
Page Object
public class LoginPage extends
FluentPage {
@AjaxElement(timeoutOnSeconds=3)
FluentWebElement ajaxElem;
}
PAGE OBJECT
And more …
Javascript
Screenshot
Direct access
Isolated tests
= new IsolatedTest().
goTo(DEFAULT_URL).
await().
atMost(1, SECONDS).
until(".small").
with("name").equalTo...
Isolated tests
= new IsolatedTest(myDriver).
goTo(DEFAULT_URL).
await().
atMost(1, SECONDS).
until(".small").
with("name")...
1 Browser /
Test
Slow
Really !
@SharedDriver
ONCE
PER_CLASS
PER_METHOD
ONCE
Test A – Method A => D1
Test A – Method B => D1
Test B – Method A => D1
PER_CLASS
Test A – Method A => D1
Test A – Method B => D1
Test B – Method A => D2
PER_METHOD
Test A – Method A => D1
Test A – Method B => D2
Test B – Method A => D3
CUCUMBER
Plain text
Automated
BDD
Scenario: Search by topic
Given there are 240 courses which do not
have the topic "biology"
And there are 2 courses A001, ...
Feature: basic test
Scenario: scenario 1
Given feature I am on the first page
When feature I click on next page
Then featu...
@Given(value = "feature I am o
the first page")
public void step1() {
this.initFluent();
this.initTest();
goTo(page);
}
@When(value = "feature I
click on next page")
public void step2() {
this.initFluent();
this.initTest();
click(“a#linkToPag...
@Then(value = "feature I am on
the second page")
public void step3() {
this.initFluent();
this.initTest();
page2.isAt();
}
#1. Do not use
Selenium IDE
#2. World > XPath
#3. Use the Page
Object pattern
#4. Separate data
and test logic
#5. One test, one
assert
#6. Test code as
clean as functionnal
code
#7. Think //
#8. Build atomic
tests
#9. Do not be
limitated by the UI
#10. Industrialize
your tests
#11. Think
incremental
#12. A story of trust
Thank you !
fluentlenium.org
@MathildeLemee
Fluentlenium
Upcoming SlideShare
Loading in...5
×

Fluentlenium

5,780

Published on

Would you like to automate your acceptance tests against multiple browsers and multiple servers? How about make your UI tests run faster? And remove the boilerplate on them? Browser automation tools to the rescue! In this session, I'll share how you can gain back development time by using FluentLenium, an open source Java wrapper around the Selenium API. We'll take a brief look at what is new in the UI testing javascript ecosystem and then I’ll share with you some rules for writing better UI tests.

Published in: Technology, Education
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
5,780
On Slideshare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
33
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide
  • Hello, Thanks for coming.My name is Mathilde Lemee, I’m a java developper.I’m a QA Engineer for terracotta, a company specialized in in-memory caching and scaling. I’m also a Java User Group founder in France, one that focus women in Java and I do some mobile developpement on iPhone and Android - some kid apps to help children learning. Today we will talk about a fluent wrapper in top of the Java API, FluentLenium.
  • , I suppose that every body already know that selenium, stop me if it’s not the case. So Selenium is a great tool for testing UI, it’s open-source, stable, it supports a lot of browsers.Selenium WebDriver brings us a lot of new features, it’s now really much faster than before with selenium RCYou also have no need to run a separate server except on special cases (if you want to use Selenium Grid).Gone are wait_for_page_to_load(), wait_for_element_present(), etc. All element interactions, clicks, etc. are blocking now, which is good. We also have some tool to use the Page object Pattern, that is a pattern that everybody should really know.
  • Another thing is that Seleniumis also available in a lot of langages. Let’s do a small poll. How many of you are using the Selenium .NET API ? Python ? Ruby ? Java ? Perl ? PHP ? Another one ?So that’s pretty cool. But as a Java user, sometimes, the JAVA api is not enough. The way to deal with AJAX stuff for example, the API don’t really fit my need so I try to look about other API than just the java API. The first I found was Geb.
  • The first is GEB. GEB is a groovy wrapper around Selenium API.It brings together the power of WebDriver, the elegance of jQuery content selection, the robustness of Page Object modelling and the expressiveness of the Groovy language.It can be used for scripting, scraping and general automation — or equally as a functional/web/acceptance testing solution via integration with testing frameworks such asSpock, JUnit & TestNG.
  • Browser.drive {    go "http://google.com/ncr"    assert title == "Google”    $("input", name: "q").value("wikipedia”)     waitFor { title.endsWith("Google Search") }deffirstLink = $("li.g", 0).find("a.l")    assertfirstLink.text() == "Wikipedia”    firstLink.click()    waitFor { title == "Wikipedia" }
  • The second lib I found after GEB was, Capybara is a ruby library. It can talk with many different drivers which execute your tests through the same clean and simple interface. You can seamlessly choose between Selenium, Webkit or pure Ruby drivers.Tackle the asynchronous web with Capybara's powerful synchronization features. Capybara automatically waits for your content to appear on the page, you never have to issue any manual sleeps.
  • def login!    within("//form[@id='session']")do      fill_in'Login', :with=>'user@example.com'      fill_in'Password', :with=>'password'    end    click_link'Sign in'  end
  • So with all of that, I try to look about what we have and what the teams I work in needed. First thing is Java. We are Java developpers and for some reason we cannot switch the langage we use. We also are front dev so javascript is something we also manipulate a lot. And with Javascript come JQUEry. And with Jquery, also CSS, because jquery use a css like syntax for selecting the elements. So we put all of that in a shaker, shake a little bit and FluentLenium is born.
  • So we put all of that in a shaker, shake a little bit and FluentLenium is born.
  • As we discuss, most of the java/javascriptdev are fluent with the css syntax because it’s really easy to understand, rules are clear and you can do most of the stuff you want. So to target a element in the dom, just use find with the css selector. Just a remember on CSS, # means the element that have the id.“a” means the balise (traduction) so all link in the page.myClassneabs the elements that have the class myClass
  • But because every people has a good level in css, we offer a fluent API to filter the dom elements. For exemple,, here, you select all the DOM element that havethe class small and the name foo
  • So, we know how we can have access to the dom element.
  • So, we know how we can have access to the dom element.
  • So, we know how we can have access to the dom element.
  • So, we know how we can have access to the dom element.
  • So, we know how we can have access to the dom element.
  • So, we know how we can have access to the dom element.
  • If you use the singular (getText instead of getTexts), it will automaticall take the text of the first element on the list.So you have getText but also getName, getId, getValue, getAtribute…
  • If you use the singular (getText instead of getTexts), it will automaticall take the text of the first element on the list
  • But now, how can we interact with the elements ?
  • ill("input").with("bar") or find("input").text("bar") will fill all the input elements with bar. If you want for example to exclude checkboxes, you can use the css filtering like fill("input:not([type='checkbox'])").with("tomato"), you can also use the filtering provided by FluentLenium fill("input", with("type", notContains("checkbox"))).with("tomato")fill("input").with("myLogin","myPassword") will fill the first element of the input selection with myLogin, the second with myPassword. If there are more input elements found, the last value (myPassword) will be repeated for each subsequent element.Don't forget, only visible fields will be modified. It simulates a real person using a browser!
  • So now, we know the basics of the API, how we use another browser but that will not help us to write readable tests. Writing readable tests should always be in our mind when we are writing tests, no matter the tests. Because you can have a the better API in the world, if your test look like that => Clique suivant
  • , you will have some troubles in the near future. So let’s go back with our Page Object Pattern.
  • Selenium tests can easily become a mess. To avoid this, you can use the Page Object Pattern. Page Object Pattern will enclose all the plumbing relating to how pages interact with each other and how the user interacts with the page, which makes tests a lot easier to read and to maintain.It will really help you to have tests that are readable and maintenable.Try to construct your Page thinking that it is better if you offer services from your page rather than just the internals of the page. A Page Object can model the whole page or just a part of it.
  •  It's simplest to think of the methods on a Page Object as offering the "services" that a page offers rather than exposing the details and mechanics of the page. Usually, a page object should not have any assertions on it. In fact, it’s hiding the internals of the page (like the id of the dom element, the dom interactions).
  • To construct a Page, extend org.fluentlenium.core.FluentPage. In most cases, you have to define the url of the page by overriding the getUrl method. By doing this, you can then use the goTo(myPage) method in your test code.It may be necessary to ensure that you are on the right page, not just at the url returned by getUrl. To do this, override the isAt method to run all the assertions necessary in order to ensure that you are on the right page. For example, if I choose that the title will be sufficient to know if I'm on the right page:
  • Create your own methods to easily fill out forms, go to another or whatever else may be needed in your test.
  • And that’s the corresponding test.
  • But it can be simpler. Within a page, all FluentWebElement fields are automatically searched for by name or id. For example, if you declare a FluentWebElement named createButton, it will search the page for an element where id is createButton or name is createButton. All elements are proxified which means that the search is not done until you try to access the element.
  • So now, that we know how to create test using the page object pattern, change the browser and manipulate the dom using the API, we should speak about AJAX call. Because asynchronous call is something really common. Your first option is to defined global timeout. The first one withDefaultSearchWait will define the max time used to search for an element in the page (equivalent of driver.manage().timeouts().implicitWait(). The second, withDefaultPageWait, will defined the maximum time for a page to be loaded.But even if defined global timeout can fix a timeout problem, sometimes, we need to be more precise.
  • 'greaterThan(int)', 'lessThan(int)', 'lessThanOrEqualTo(int)', 'greaterThanOrEqualTo(int)' , 'equalTo(int)', 'notEqualTo(int)'
  • startsWith, notStartsWith, endsWith, notEndsWith, contains,notContains, equalTo, containsWord.And you can also define the polling if needed with pollingEvery.
  • startsWith, notStartsWith, endsWith, notEndsWith, contains,notContains, equalTo, containsWord.And you can also define the polling if needed with pollingEvery.
  • startsWith, notStartsWith, endsWith, notEndsWith, contains,notContains, equalTo, containsWord.And you can also define the polling if needed with pollingEvery.
  • So what’s about the page object pattern ? Because everything is made to
  • You can set the timeout in seconds for the page to throw an error if not found with@AjaxElement(timeountOnSeconds=3) if you want to wait 3 seconds. By default, the timeout is set to one second.
  • And you have a lot of other features, you can of course execute some javascript using the executeJavascript method, take screenshot when you want or when a test fail with jUnit for example, and something really important for us : you ALWAYS have access to the selenium driver, so we guarantee that everything you do with that driver, you will be able to do inside FluentLenium
  • We also have the isolated test, where tests are isolated. They do not depends on a FluentTest, you can embed everywhere.
  • You can also give as a parameter a driver, which is a way (there are a lot) to play the same tests with differents browsers.
  • At the beginning, one browser will be launch by test. It’s a godd way to avoid unexpected collisions between the test but because of that, it was
  • Now Use the class annotation @SharedDriver and you will be able to defined how the driver will be created :@SharedDriver(type = SharedDriver.SharedType.ONCE)will allow you to use the same driver for every test annotate with that annotation (it can also be on a parent class) for all classes and methods.@SharedDriver(type = SharedDriver.SharedType.PER_CLASS)will allow you to use the same driver for every test annotate with that annotation (it can also be on a parent class) for all methods on a same class.@SharedDriver(type = SharedDriver.SharedType.PER_METHOD)will allow you to create a new driver for each method.
  • Now Use the class annotation @SharedDriver and you will be able to defined how the driver will be created :@SharedDriver(type = SharedDriver.SharedType.ONCE)will allow you to use the same driver for every test annotate with that annotation (it can also be on a parent class) for all classes and methods.@SharedDriver(type = SharedDriver.SharedType.PER_CLASS)will allow you to use the same driver for every test annotate with that annotation (it can also be on a parent class) for all methods on a same class.@SharedDriver(type = SharedDriver.SharedType.PER_METHOD)will allow you to create a new driver for each method.
  • Now Use the class annotation @SharedDriver and you will be able to defined how the driver will be created :@SharedDriver(type = SharedDriver.SharedType.ONCE)will allow you to use the same driver for every test annotate with that annotation (it can also be on a parent class) for all classes and methods.@SharedDriver(type = SharedDriver.SharedType.PER_CLASS)will allow you to use the same driver for every test annotate with that annotation (it can also be on a parent class) for all methods on a same class.@SharedDriver(type = SharedDriver.SharedType.PER_METHOD)will allow you to create a new driver for each method.
  • Now Use the class annotation @SharedDriver and you will be able to defined how the driver will be created :@SharedDriver(type = SharedDriver.SharedType.ONCE)will allow you to use the same driver for every test annotate with that annotation (it can also be on a parent class) for all classes and methods.@SharedDriver(type = SharedDriver.SharedType.PER_CLASS)will allow you to use the same driver for every test annotate with that annotation (it can also be on a parent class) for all methods on a same class.@SharedDriver(type = SharedDriver.SharedType.PER_METHOD)will allow you to create a new driver for each method.
  • Cucumber is a tool that executes plain-text functional descriptions as automated tests. While Cucumber can be thought of as a “testing” tool, the intent of the tool is to support BDD. This means that the “tests” (plain text feature descriptions with scenarios) are typically written before anything else and verified by business analysts, domain experts, etc. non technical stakeholders.
  • So the non technical people will be able to write a lot of tests like this. You will have to defined what we call the “step” to make the bridge between the plain text line and the action.
  • Fluentlenium

    1. 1. Fluent Lenium Another way of using Selenium in Java
    2. 2. Mathilde Lemée Terracotta QA Engineer DuchessFR Founder Mobile dev – Aetys.fr Java developper FluentLenium
    3. 3. GREAT tool
    4. 4. Ruby APIS Python Java .NET Perl PHP
    5. 5. GEB WebDriver Groovy Jquery Page object
    6. 6. Browser.drive { go "http://google.com/ncr" assert title == "Google” $("input", name: "q").value("wikipedia”) waitFor { title.endsWith("Google Search") } def firstLink = $("li.g", 0).find("a.l") assert firstLink.text() == "Wikipedia" firstLink.click() waitFor { title == "Wikipedia" }
    7. 7. Capybara Ruby Selenium Webkit Ruby drivers Automatically waits
    8. 8. def login! within("//form[@id='session']") do fill_in 'Login', :with => 'user@example.com' fill_in 'Password', :with => 'password' end click_link 'Sign in' end
    9. 9. Java Javascript jQuery CSS
    10. 10. Fluent Lenium
    11. 11. find(“a”) find(“#id”) find(“.myClass”) TARGET
    12. 12. find(".small", withName("foo")) FILTER
    13. 13. find(".small", withClass("foo")) FILTER
    14. 14. find(".small", withId("foo")) FILTER
    15. 15. find(".small", withText("foo")) FILTER
    16. 16. find(".small", withAttribute(”at”) .equalTo(”foo”)) FILTER
    17. 17. find(".small", withId(). contains(”foo”)) FILTER
    18. 18. find(".small", withId(). containsWord(”foo”)) FILTER
    19. 19. find(".small", withId(). startsWith(”foo”)) FILTER
    20. 20. find(".small", withId(). endsWith(”foo”)) FILTER
    21. 21. find(".small", withId().contains( Pattern.compile ("abc*"))) FILTER
    22. 22. find(".small", withName("foo")) find(".small” ).first() FINDfind(".small") find(".small", withName(). startsWith(”my")
    23. 23. ACCESS find(".small").getNames()
    24. 24. ACCESS find(".small").getIds()
    25. 25. ACCESS find(".small").getValues()
    26. 26. ACCESS find(".small").getTexts()
    27. 27. ACCESS find(".small"). getAttributes(”custom")
    28. 28. ACCESS find(".small"). getText()
    29. 29. ACCESS find(".small"). html()
    30. 30. ACTIONS goTo(“http://www.google.fr”) click("#create-button") doubleClick("#create-button")
    31. 31. FILL fill("input").with("m yLogin","myPassw ord") fill("#name").with("Mathilde") find("#name").text("Mathilde") fill("input:not([type='checkbox'])").with("tomato") fill("input", with("type", notContains("checkbox"))).with("t omato")
    32. 32. FORM submit(“#myForm”) clear("#myForm") fill(“#name”).with(“Mathilde”)
    33. 33. ASSERTIONS Your own assertThat(title()).contains("Hello "); assertThat(find(myCssSelecto2)).ha sSize().lessThan(5);
    34. 34. public class BingTest extends FluentTest { @Test public void title_should_contain_query() { goTo("http://www.bing.com"); fill("#sb_form_q").with("FluentLenium"); submit("#sb_form_go"); assertThat(title()) .contains("FluentLenium"); } } Example 1
    35. 35. PAGE OBJECT PATTERN
    36. 36. Why ? Readable Maintenable Separate concerns
    37. 37. How? No assertions Services Hide internals of the page
    38. 38. FluentPage isAt methods getUrl
    39. 39. public class LoginPage extends FluentPage { public String getUrl() { return "myCustomUrl"; } public void isAt() { assertThat(title()).isEqualTo("MyTitle"); } public void fillAndSubmitForm(String... paramsOrdered) { fill("input").with(paramsOrdered); click("#create-button"); } }
    40. 40. @Page LoginPage loginPage; public void checkLoginFailed() { goTo(loginPage); loginPage. fillAndSubmitLoginForm("login", ”wp"); assertThat(find(".error")).hasSize(1); loginPage.isAt(); }
    41. 41. public class LoginPage extends FluentPage { FluentWebElement createButton; public String getUrl() { return "myCustomUrl"; } public void isAt() { assertThat(title()).isEqualTo("MyTitle"); } public void fillAndSubmitForm(String... paramsOrdered) { fill("input").with(paramsOrdered); createButton.click(); } }
    42. 42. AWAIT withDefaultSearchWait(long l, TimeUnit timeUnit); withDefaultPageWait(long l, TimeUnit timeUnit);
    43. 43. isPresent() await(). atMost(5,SECONDS). until(".small").
    44. 44. await(). atMost(5,SECONDS). until(".small"). hasName("name");
    45. 45. await(). atMost(5,SECONDS). until(".small"). hasText(”text");
    46. 46. await(). atMost(5,SECONDS). until(".small").containsText(”txt");
    47. 47. await(). atMost(5,SECONDS). until(".small"). hasId("id");
    48. 48. await(). atMost(5,SECONDS). until(".small"). hasSize(3);
    49. 49. await(). atMost(5,SECONDS). until(".small"). hasSize(). greatherThan(3);
    50. 50. await(). atMost(5,SECONDS). until(".small"). withText("myText").areDis played();
    51. 51. await(). atMost(5,SECONDS). until(".small"). withId("#id"). areEnabled();
    52. 52. await(). atMost(5,SECONDS). until(".small"). with(”attribute"). startsWith(”xyz") isPresent();
    53. 53. await(). atMost(5,SECONDS). untilPage() isLoaded();
    54. 54. await(). atMost(5,SECONDS). untilPage() isLoaded();
    55. 55. public class LoginPage extends FluentPage { @AjaxElement FluentWebElement ajaxElem; } Page Object
    56. 56. public class LoginPage extends FluentPage { @AjaxElement(timeoutOnSeconds=3) FluentWebElement ajaxElem; } PAGE OBJECT
    57. 57. And more … Javascript Screenshot Direct access
    58. 58. Isolated tests = new IsolatedTest(). goTo(DEFAULT_URL). await(). atMost(1, SECONDS). until(".small"). with("name").equalTo("name"). isPresent(). find("input"). first(). isEnabled();
    59. 59. Isolated tests = new IsolatedTest(myDriver). goTo(DEFAULT_URL). await(). atMost(1, SECONDS). until(".small"). with("name").equalTo("name"). isPresent(). find("input"). first(). isEnabled();
    60. 60. 1 Browser / Test
    61. 61. Slow
    62. 62. Really !
    63. 63. @SharedDriver ONCE PER_CLASS PER_METHOD
    64. 64. ONCE Test A – Method A => D1 Test A – Method B => D1 Test B – Method A => D1
    65. 65. PER_CLASS Test A – Method A => D1 Test A – Method B => D1 Test B – Method A => D2
    66. 66. PER_METHOD Test A – Method A => D1 Test A – Method B => D2 Test B – Method A => D3
    67. 67. CUCUMBER Plain text Automated BDD
    68. 68. Scenario: Search by topic Given there are 240 courses which do not have the topic "biology" And there are 2 courses A001, B205 that each have "biology" as one of the topics When I search for "biology" Then I should see the following courses: | Course code | | A001 | | B205 |
    69. 69. Feature: basic test Scenario: scenario 1 Given feature I am on the first page When feature I click on next page Then feature I am on the second page
    70. 70. @Given(value = "feature I am o the first page") public void step1() { this.initFluent(); this.initTest(); goTo(page); }
    71. 71. @When(value = "feature I click on next page") public void step2() { this.initFluent(); this.initTest(); click(“a#linkToPage2" ); }
    72. 72. @Then(value = "feature I am on the second page") public void step3() { this.initFluent(); this.initTest(); page2.isAt(); }
    73. 73. #1. Do not use Selenium IDE
    74. 74. #2. World > XPath
    75. 75. #3. Use the Page Object pattern
    76. 76. #4. Separate data and test logic
    77. 77. #5. One test, one assert
    78. 78. #6. Test code as clean as functionnal code
    79. 79. #7. Think //
    80. 80. #8. Build atomic tests
    81. 81. #9. Do not be limitated by the UI
    82. 82. #10. Industrialize your tests
    83. 83. #11. Think incremental
    84. 84. #12. A story of trust
    85. 85. Thank you ! fluentlenium.org @MathildeLemee
    1. A particular slide catching your eye?

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

    ×