Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

SWTBot Essentials

SWTBot Essentials

A brief presentation on working with SWTBot

Chris Aniszczyk

November 12, 2009
Tweet

More Decks by Chris Aniszczyk

Other Decks in Programming

Transcript

  1. creating a java project “MyFirstProject” create a java class type

    in a program that prints “Hello, World” execute the program verify that the program printed “Hello, World” All exercises focus around...
  2. Create a simple Test @RunWith(SWTBotJunit4ClassRunner.class) public class Test01 { @Test

    public void thisOneFails() throws Exception { fail("this test fails"); } @Test public void thisOnePasses() throws Exception { pass(); } }
  3. Finding widgets SWTWorkbenchBot bot = new SWTWorkbenchBot(); SWTBot[Widget] widget =

    bot.[widget][With][Matcher(s)](); SWTBotText text = bot.textWithLabel("Username:"); Think of the bot as something that can do tasks for you (e.g., find widgets, click on them, etc.)
  4. Finding obscure widgets withLabel("Username:") withMnemonic("Finish") withText("&Finish") inGroup("Billing Address") widgetOfType(Button.class) withStyle(SWT.RADIO)

    withTooltip("Save All") withRegex("Welcome, (.*)") Use matchers and WidgetMatcherFactory! Matcher pushButtonToProceedToNextStep = allOf( widgetOfType(Button.class), withStyle(SWT.PUSH), withRegex("Proceed to step (.*) >") ); SWTBotButton button = new SWTBotButton( (Button) bot.widget (pushButtonToProceedToNextStep) );
  5. Performing actions button.click() // click on a button // chain

    methods to make them concise bot.menu("File").menu("New").menu("Project...").click(); tree.expand("Project").expand("src").expand("Foo.java").contextMenu ("Delete").click(); // delete Foo.java list.select("Orange", "Banana", "Mango"); // make a selection in a list list.select(2, 5, 6); // make a selection using indexes
  6. Get introduced to the SWTBot API SWTWorkbenchBot is your friend

    Tasks beforeClass() - close the welcome view canCreateANewProject() - create a java project Run the test! Ensure SWTBot logging works Objectives
  7. beforeClass() @BeforeClass public static void beforeClass() throws Exception { bot

    = new SWTWorkbenchBot(); bot.viewByTitle("Welcome").close(); }
  8. canCreateANewProject() @Test public void canCreateANewJavaProject() throws Exception { bot.menu("File").menu("New").menu("Project...").click(); SWTBotShell

    shell = bot.shell("New Project"); shell.activate(); bot.tree().select("Java Project"); bot.button("Next >").click(); bot.textWithLabel("Project name:").setText("MyFirstProject"); bot.button("Finish").click(); }
  9. Find all widgets Depth first traversal of UI elements 1.Find

    top level widgets 1.Find children of each widget 2.For each child do (1) and (2)
  10. Finding widgets public SWTBotTree treeWithLabelInGroup(String l, String g, int i)

    { // create the matcher Matcher matcher = allOf( widgetOfType(Tree.class), withLabel(l), inGroup(g) ); // find the widget, with redundancy built in Tree tree = (Tree) widget(matcher, index); // create a wrapper for thread safety // and convinience APIs return new SWTBotTree(tree, matcher); }
  11. Thread Safety (Query state) public class SWTBotCheckBox { public boolean

    isChecked() { // evaluate a result on the UI thread return syncExec(new BoolResult() { public Boolean run() { return widget.getSelection(); } }); } }
  12. Thread Safety(change state) public class SWTBotCheckBox { public void select()

    { asyncExec(new VoidResult() { public void run() { widget.setSelection(true); } }); notifyListeners(); } protected void notifyListeners() { notify(SWT.MouseDown); notify(SWT.MouseUp); notify(SWT.Selection); } }
  13. Tasks canCreateANewJavaClass() create a new java class: HelloWorld Source folder:

    MyFirstProject/src Package: org.eclipsecon.project Click Finish! Run the test! Objectives
  14. canCreateANewJavaClass() @Test public void canCreateANewJavaClass() throws Exception { bot.toolbarDropDownButtonWithTooltip("New Java

    Class").menuItem("Class").click(); bot.shell("New Java Class").activate(); bot.textWithLabel("Source folder:").setText("MyFirstProject/src"); bot.textWithLabel("Package:").setText("org.eclipsecon.project"); bot.textWithLabel("Name:").setText("HelloWorld"); bot.button("Finish").click(); }
  15. Tasks canTypeInTextInAJavaClass() open a file: HelloWorld.java set some text in

    the Java file canExecuteJavaApplication() Run the Java application Run the test! Objectives
  16. canTypeInTextInAJavaClass() @Test public void canTypeInTextInAJavaClass() throws Exception { Bundle bundle

    = Activator.getContext().getBundle(); String contents = FileUtils.read(bundle.getEntry("test-files/HelloWorld.java")); SWTBotEditor editor = bot.editorByTitle("HelloWorld.java"); SWTBotEclipseEditor e = editor.toTextEditor(); e.setText(contents); editor.save(); }
  17. Learn about SWTBot and the Matcher API Tasks canExecuteJavaApplication() Run

    the Java application Grab the Console view Verify that “Hello World” is printed Run the tests! Objectives
  18. canExecuteJavaApplication() @Test public void canExecuteJavaApplication() throws Exception { bot.menu("Run").menu("Run").click(); SWTBotView

    view = bot.viewByTitle("Console"); Widget consoleViewComposite = view.getWidget(); StyledText console = bot.widget(WidgetMatcherFactory.widgetOfType (StyledText.class), consoleViewComposite); SWTBotStyledText styledText = new SWTBotStyledText(console); assertTextContains("Hello World", styledText); }
  19. Matchers Under the covers, SWTBot uses Hamcrest Hamcrest is a

    framework for writing ‘match’ rules SWTBot is essentially all about match rules bot.widget (WidgetMatcherFactory.widgetOfType (StyledText.class), consoleViewComposite);
  20. Learn about waiting and SWTBot Condition API Tasks afterClass() Select

    the Package Explorer view Select MyFirstProject Right click and delete the project Run the test! Objectives
  21. afterClass() @AfterClass public static void afterClass() throws Exception { SWTBotView

    packageExplorerView = bot.viewByTitle("Package Explorer"); packageExplorerView.show(); Composite packageExplorerComposite = (Composite) packageExplorerView.getWidget(); Tree swtTree = (Tree) bot.widget(WidgetMatcherFactory.widgetOfType(Tree.class), packageExplorerComposite); SWTBotTree tree = new SWTBotTree(swtTree); tree.select("MyFirstProject"); bot.menu("Edit").menu("Delete").click(); // the project deletion confirmation dialog SWTBotShell shell = bot.shell("Delete Resources"); shell.activate(); bot.checkBox("Delete project contents on disk (cannot be undone)").select(); bot.button("OK").click(); bot.waitUntil(shellCloses(shell)); }
  22. Handling long operations describe a condition poll for the condition

    at intervals wait for it to evaluate to true or false of course there’s a timeout SWTBot has an ICondition
  23. Handling Waits private void waitUntil(ICondition condition, long timeout, long interval)

    { long limit = System.currentTimeMillis() + timeout; condition.init((SWTBot) this); while (true) { try { if (condition.test()) return; } catch (Throwable e) { // do nothing } sleep(interval); if (System.currentTimeMillis() > limit) throw new TimeoutException("Timeout after: " + timeout); } }
  24. Abstractions are good! They simplify writing tests for QA folks

    Build page objects for common “services” Project Explorer The Editor The Console View The main menu bar, tool bar
  25. Sample Domain Object public class JavaProject { public JavaProject create(String

    projectName){ // create a project and return it } public JavaProject delete(){ // delete the project and return it } public JavaClass createClass(String className){ // create a class and return it } }
  26. Page Objects? Represent the services offered by the page to

    the test developer Internally knows the details about how these services are offered and the details of UI elements that offer them Return other page objects to model the user’s journey through the application Different results of the same operation modeled
  27. A Sample Page Object public class LoginPage { public HomePage

    loginAs(String user, String pass) { // ... clever magic happens here } public LoginPage loginAsExpectingError(String user, String pass) { // ... failed login here, maybe because one or both of // username and password are wrong } public String getErrorMessage() { // So we can verify that the correct error is shown } }
  28. Using Page Objects // the bad test public void testMessagesAreReadOrUnread()

    { Inbox inbox = new Inbox(driver); inbox.assertMessageWithSubjectIsUnread("I like cheese"); inbox.assertMessageWithSubjectIsNotUndread("I'm not fond of tofu"); } // the good test public void testMessagesAreReadOrUnread() { Inbox inbox = new Inbox(driver); assertTrue(inbox.isMessageWithSubjectIsUnread("I like cheese")); assertFalse(inbox.isMessageWithSubjectIsUnread("I'm not fond of tofu")); }
  29. LoginPage login = new LoginPage(); HomePage home = login.loginAs("username", "secret");

    SearchPage search = home.searchFor("swtbot"); assertTrue(search.containsResult("http://eclipse.org/swtbot"));
  30. Learn about page and domain objects Tasks Create a NewProjectBot

    Opens the new project wizard Allows you to set the project name and click finish Modify canCreateANewJavaProject() Run the test! Objectives
  31. NewProjectBot public class NewProjectBot { private static SWTWorkbenchBot bot; public

    NewProjectBot() { bot.menu("File").menu("New").menu("Project...").click(); bot.shell("New Project").activate(); bot.tree().select("Java Project"); bot.button("Next >").click(); } public void setProjectName(String projectName) { bot.textWithLabel("Project name:").setText(projectName); } public void finish() { bot.button("Finish").click(); } }
  32. Modify Project Wizard Code @Test public void canCreateANewJavaProject() throws Exception

    { // use the NewProjectBot abstraction NewProjectBot newProjectBot = new NewProjectBot(); newProjectBot.setProjectName("MyFirstProject"); newProjectBot.finish(); assertProjectCreated(); }
  33. Useful for debugging at times... SWTBotPreferences.PLAYBACK_DELAY -Dorg.eclipse.swtbot.playback.delay=20 or via code...

    Slow down executions long oldDelay = SWTBotPreferences.PLAYBACK_DELAY; // increase the delay SWTBotPreferences.PLAYBACK_DELAY = 10; // do whatever // set to the original timeout of 5 seconds SWTBotPreferences.PLAYBACK_DELAY = oldDelay;
  34. SWTBotPreferences.TIMEOUT -Dorg.eclipse.swtbot.search.timeout=10000 or via code... Changing Timeout long oldTimeout =

    SWTBotPreferences.TIMEOUT; // increase the timeout SWTBotPreferences.TIMEOUT = 10000; // do whatever // set to the original timeout of 5 seconds SWTBotPreferences.TIMEOUT = oldTimeout;
  35. In our examples, we used labels as matchers mostly SWTBot

    allows you to use IDs as matchers IDs are less brittle than labels! text.setData (SWTBotPreferences.DEFAULT_KEY,”id”) bot.textWithId(“id”) Identifiers
  36. Use Page Objects to simplify writing tests Allows more people

    than just normal devs to write tests Page Objects
  37. More SWTBot? Eclipse Forms support in HEAD GEF support is

    available for graphical editor testing