Functional Testing Swing Applications with Frankenstein


Published on

Presentation on Functional Testing Swing Applications with Frankenstein, an Open Source testing tool

Published in: Business, Technology
1 Comment
  • Fantastic presentation Vivek. Btw, it would be great if you could help me with your views on software testing certifications! I'm presently considering QAI's offerings -
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Functional Testing Swing Applications with Frankenstein

  1. 1. <ul><li>Functional Testing Swing Applications with Frankenstein </li></ul>Vivek Prahlad
  2. 2. Agenda <ul><li>Introduction to Frankenstein: </li></ul><ul><ul><li>What is it? </li></ul></ul><ul><ul><li>Origin </li></ul></ul><ul><ul><li>How does it work? </li></ul></ul><ul><ul><li>Features </li></ul></ul><ul><li>Demo </li></ul>
  3. 3. What is Frankenstein <ul><li>Record and Play tool for testing Swing Applications </li></ul><ul><li>Support for testing Multithreaded Applications </li></ul><ul><li>Ruby driver </li></ul><ul><li>Easy extension </li></ul>
  4. 4. Origins <ul><li>Originated on a ThoughtWorks project with a Swing UI </li></ul><ul><ul><li>Multithreaded user interface </li></ul></ul><ul><ul><li>Custom components (date pickers, etc.) </li></ul></ul><ul><li>Functional testing tools (commercial and open source) inadequate </li></ul><ul><ul><li>Slow, inadequate support for testing multithreaded apps </li></ul></ul><ul><ul><li>Poor custom component support </li></ul></ul><ul><ul><li>Build integration </li></ul></ul><ul><ul><li>License cost for commercial tools </li></ul></ul>
  5. 5. Features <ul><li>Record and play support </li></ul><ul><li>Performance </li></ul><ul><li>Ruby driver </li></ul><ul><li>OGNL based assertions </li></ul><ul><li>Multithreaded application support </li></ul><ul><li>Easy extension / customization </li></ul><ul><li>Straightforward integration </li></ul><ul><li>HTML Reports </li></ul><ul><ul><li>Records screenshot on test step failure </li></ul></ul><ul><ul><li>Reports can be customized </li></ul></ul>
  6. 6. How does it work? <ul><li>Recorders hook on to Swing Event Queue </li></ul><ul><li>Attach component specific listeners </li></ul><ul><li>Record Events when the user interacts with the UI </li></ul><ul><ul><li>Event coalescing attempts to minimize script size </li></ul></ul><ul><li>Events can replay themselves </li></ul>
  7. 7. Record and play support <ul><li>Recording for reproducing bugs </li></ul><ul><li>Not advisable to record entire scenarios </li></ul><ul><ul><li>Scripts become unmaintainable, difficult to read </li></ul></ul><ul><li>A better way is to record snippets of a user's workflow </li></ul><ul><ul><li>Can extract functions, parameterize </li></ul></ul><ul><li>Later, library functions can be used to write tests from scratch </li></ul>
  8. 8. Ruby driver <ul><li>Helps make tests modular </li></ul><ul><ul><li>Extract common steps into functions </li></ul></ul><ul><ul><li>Parameterize functions </li></ul></ul><ul><li>Build a vocabulary for your application </li></ul><ul><li>Test Suite support </li></ul>
  9. 9. Why Ruby? <ul><li>Ruby is a full-featured object oriented language </li></ul><ul><li>Focus on readability, ease of use </li></ul><ul><li>Allows test scripts to be modularized </li></ul><ul><li>Lots of flexibility: </li></ul><ul><ul><li>Connect to databases </li></ul></ul><ul><ul><li>Externalize strings (for i18n testing) </li></ul></ul><ul><ul><li>CSV support </li></ul></ul>
  10. 10. Recording + Ruby <ul><li>In combination, it is possible to build a testing vocabulary very close to the domain. </li></ul><ul><li>Example: </li></ul><ul><ul><li>login username, password </li></ul></ul><ul><ul><li>check_balance_is 1100 </li></ul></ul><ul><ul><li>transfer destination_account_number </li></ul></ul><ul><ul><li>check_balance_is 1000 </li></ul></ul>
  11. 11. Assertions <ul><li>Control-rightclick on text and labels records assertions </li></ul><ul><ul><li>Need to add additional assertions manually using the Ruby driver </li></ul></ul><ul><li>Assert arbitrary properties via OGNL: </li></ul><ul><ul><li>assert “table_name” , “tableModel.rowCount” , “1” </li></ul></ul><ul><ul><li>Equivalent to: </li></ul></ul><ul><ul><li>assertEquals (1 , table.getTableModel().getRowCount()) </li></ul></ul><ul><li>Can even make method calls! </li></ul><ul><ul><li>assert “table_name” “getValueAt(0,0)” , “cell text at row 0, column 0” </li></ul></ul><ul><li>Check out Ruby driver for examples </li></ul><ul><li> for information about OGNL </li></ul>
  12. 12. Testing Multithreaded apps <ul><li>Two basic approaches exist: </li></ul><ul><li>Arbitrary waits </li></ul><ul><ul><li>Make a guess about when an action will complete </li></ul></ul><ul><li>Explicit synchronization </li></ul><ul><ul><li>Look for indirect indications that actions are complete </li></ul></ul>
  13. 13. Abitrary waits <ul><li>Tests are either: </li></ul><ul><ul><li>Slow, if the delays are more than required </li></ul></ul><ul><ul><li>Fragile, if the delays are less than required </li></ul></ul><ul><li>Example: </li></ul><ul><li>login username, password </li></ul><ul><li>wait(20) </li></ul><ul><li>navigate inbox </li></ul><ul><li>select all </li></ul><ul><li>delete </li></ul>
  14. 14. Explicit Synchronization <ul><li>Tests tend to be verbose </li></ul><ul><li>Example: </li></ul><ul><li>login username, password </li></ul><ul><li>wait_for_label(username) </li></ul><ul><li>navigate inbox </li></ul><ul><li>select all </li></ul><ul><li>delete </li></ul><ul><li>wait_for_label in turn uses a delay within a loop </li></ul>
  15. 15. Frankenstein Approach <ul><li>Scripts do not need to worry about threading issues </li></ul><ul><li>The framework does it for you </li></ul><ul><ul><li>Decide on a worker thread naming convention </li></ul></ul><ul><ul><li>Frankenstein will monitor threads in the system after each test step </li></ul></ul><ul><li>Example </li></ul><ul><li>login username, password </li></ul><ul><li>navigate inbox </li></ul><ul><li>select all </li></ul><ul><li>delete </li></ul>
  16. 16. Integrating Frankenstein <ul><li>Logically name components ( using component.setName() ) </li></ul><ul><ul><li>Naming strategy allows testing UIs where components aren't named </li></ul></ul><ul><li>Use PipingMain to get Frankenstein to launch your app </li></ul><ul><ul><li>Typical startup script: Java .. .. </li></ul></ul><ul><ul><li>Change to: </li></ul></ul><ul><ul><li>Java .. com.thoughtworks.frankenstein.application.PipingMain .. </li></ul></ul><ul><li>Use Ant's exec task to run Ruby test suite </li></ul><ul><ul><li>Remember to launch app using PipingMain first! </li></ul></ul><ul><ul><li>May need delay before starting test run to account for app startup time </li></ul></ul><ul><ul><li><exec dir=&quot;${test.script.dir}&quot; executable=&quot;ruby.exe&quot;> </li></ul></ul><ul><ul><li><arg line=&quot;testsuite.rb&quot;/> </li></ul></ul><ul><ul><li></exec> </li></ul></ul>
  17. 17. Customizing Frankenstein <ul><li>Write a main class </li></ul><ul><ul><li>/** </li></ul></ul><ul><ul><li>* Launch the application under test via Frankenstein. </li></ul></ul><ul><ul><li>*/ </li></ul></ul><ul><ul><li>public class FrankensteinLauncher { </li></ul></ul><ul><ul><li>public static void main(String[] args) { </li></ul></ul><ul><ul><li>FrankensteinIntegration integration = new FrankensteinIntegration(YouMainClass.class); </li></ul></ul><ul><ul><li>integration.registerEvent(YourCustomEvent.class); </li></ul></ul><ul><ul><li>integration.registerRecorder(YourCustomRecorder.class); </li></ul></ul><ul><ul><li>integration.start(args); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
  18. 18. Customizing Frankenstein <ul><li>Register custom events, if any </li></ul><ul><ul><li>Most events can extend AbstractFrankensteinEvent </li></ul></ul><ul><ul><li>Use AbstractEventTestCase </li></ul></ul><ul><li>Register custom recorders, if any </li></ul><ul><ul><li>Most recorders can extend from AbstractComponentRecorder </li></ul></ul><ul><ul><li>Recorders created using IOC, so declare which of these you'll need in your recorder's constructor: </li></ul></ul><ul><ul><ul><li>NamingStrategy, Recorder, ComponentDecoder, ComponentVisibility </li></ul></ul></ul>
  19. 19. Customizing Frankenstein <ul><li>Multithreading support: </li></ul><ul><li>Decide on a worker thread naming convention, if required </li></ul><ul><ul><li>Use RegexWorkerThreadMonitor </li></ul></ul><ul><ul><li>new FrankensteinIntegration(YourMain.class, new RegexWorkerThreadMonitor(“<thread name pattern>”); </li></ul></ul><ul><li>Or implement the WorkerThreadMonitor interface </li></ul>
  20. 20. Demo
  21. 21. Get it at <ul><li> </li></ul><ul><li>Main site at </li></ul>
  22. 22. Coming Soon <ul><li>Drag and Drop support </li></ul><ul><li>Tree editor support </li></ul><ul><li>Smart renderer decoders </li></ul><ul><ul><li>Pluggable renderer decoding support </li></ul></ul><ul><li>More assertions </li></ul>