Developer Testing Stephan J. Schmidt cintoo lead developer http://cintoo.org [email protected] Achieving a hundred percent test coverage for database and Swing applications
May 11, 2015
Developer Testing
Stephan J. Schmidt
cintoo lead developer
http://cintoo.org
Achieving a hundred percent test coverage for database and Swing applications
Stephan J. Schmidt, cintoo
Contents
• What is developer testing
• Why you should practice developer testing
• How you can do developer testing
• How to test nasty things
2
Stephan J. Schmidt, cintoo
What is Developer Testing
3
Testing done by developersSimple:
Stephan J. Schmidt, cintoo
Acceptance versus Developer Tests
4
Acceptence Testing
System against Requirements
Developer Testing
Code against DesignTests:
Stephan J. Schmidt, cintoo
Why?
• Improves the health of your system
• Gives you a good feeling
• Makes you more confident
• Developer testing makes you more effective
5
Stephan J. Schmidt, cintoo
Accountability
• Developer testing leads to accountability
• Developers should be accountable for their code
• Business people often think they are
• Offshoring/ Outsourcing might be due to lack of accountability
• Accountability needed for CMM5
6
Stephan J. Schmidt, cintoo
Save time
• Less gold plating
• Developers know when to stop
• Less thinking what to do next
• Tests result in cleaner, more atomic design which reduces time when introducing new features
• Regression testing finds new bugs fast
7
Stephan J. Schmidt, cintoo
Implementing Developer Testing
• Be pragmatic!
• It’s free
• Frameworks like TestNG or xUnit (JUnit, NUnit...)
• TestCases with methods (tests) which test your classes
• Run tests automatically and frequently
• Use automatic builds (Pulse, Cruise control, ..)
• Set goals (metric based)
8
Stephan J. Schmidt, cintoo
Example adding two numbers
9
public class Math { public static int add(int a, int b) { return a + b; }}
Stephan J. Schmidt, cintoo
Testing Math with an Unit Test
10
public class TestMath { @Test public void addTwoPositiveNumbers() { Asserts.assertEquals( "2 + 3 = 5", 5, Math.add(2,3)); }
@Test public void addZero() { Asserts.assertEquals( "1 + 0 = 1", 1, Math.add(1,0)); Asserts.assertEquals( "0 + 1 = 1", 1, Math.add(0,1)); }}
Stephan J. Schmidt, cintoo
Test tools
• Tests are run with a testing tool
• Tool displays non-working tests
11
Stephan J. Schmidt, cintoo
Build Server
• Runs tests automatically on check-in or time based
• Prevents non working tests in repository after check-ins
(though they might run locally)
12
Stephan J. Schmidt, cintoo
Example application SuperAdd
• Will replace Excel!
• Adding two numbers
• Graphical user interface for data entry
• Storing the calculations in a database
13
Stephan J. Schmidt, cintoo
Architecture
• Three tier application
• Different testing scenarios for every tier
14
GUI
Logic
Storage
Stephan J. Schmidt, cintoo
Architecture
15
SwingCalcView
CalcView
CalcEditor
Math CalcManager
CalcStorage
JDBCCalcStorage
DB
Buttons
Application BorderState
Application Border State
GUI
Logic
Storage
1
2
3
Stephan J. Schmidt, cintoo
Testing SuperAdd
• Test Logic (Math, CalcManager) easy
• Test Storage (JDBCCalcStorage) not so easy
• Test GUI (CalcView, CalcEditor) hmm. some thinking needed
16
Stephan J. Schmidt, cintoo
Testing Math is easy
• Already shown, lucky me :-)
• Test for negative numbers, overflow, ...
17
MathTest
calculate / ok
1
Stephan J. Schmidt, cintoo
Testing CalcManager
• CalcManager logs correct calculations to the storage
• Problem is the usage of a database
• Testing not in isolation
• Solution is usage of Mock objects for database storage
18
1
CalcManager
MockCalcStorage
Test
set / ok
ok
Stephan J. Schmidt, cintoo
Mock objects
• In-replacement for objects
• Mocks simulate the dependencies
• Testing in isolation
• Testing classes "from below"
19
Test
Class to Test
Dependenciesas Mocks
Stephan J. Schmidt, cintoo
GUI Testing
20
2
Stephan J. Schmidt, cintoo
Usually Java GUIs look like this
21
public class View { ... calculateButton.addActionListener( ... sumField.setText( Math.add( aField.getText(), bField.getText()); )); }} Hard to test, depends on
Swing. Logic not reusablein different GUI frameworks!
Stephan J. Schmidt, cintoo
GUI splitting
• View/Editor pattern, split GUI in view and editor
• Remove ALL logic from the view
• Editor contains the logic
22
Editor
View
GUI
Stephan J. Schmidt, cintoo
View
23
public class View { ... calculateButton.addActionListener( ... editor.calculate() )); } public void setSum(int sum) { sumField.setText(sum); }}
Stephan J. Schmidt, cintoo
Editor
24
public class Editor { public void calculate() { int a = view.getAValue(); int b = view.getBValue(); view.setSum(Math.add(a,b)); }}
Logic
Stephan J. Schmidt, cintoo
Editor Test
25
@Testpublic void calculate() { Mock mockCalcView = mock(CalcView.class); mockCalcView.expects(once()) .method("getAValue").will(returnValue(2)); ... Mock mockCalcManager = mock(CalcManager.class); mockCalcManager.expects(once()) .method("logCalc").with(eq(2), eq(3), eq(5));
CalcEditor editor = new CalcEditor( (CalcView) mockCalcView.proxy(), (CalcManager) mockCalcManager.proxy()); editor.calculate();}
Stephan J. Schmidt, cintoo
GUI Testing
• Record/ Playback: Actions are recorded and after that a tester replays the recorded actions
• Click tests: Testers click buttons in a GUI according to a test plan
• Programmatic: Developer writes GUI tests with framework
• Record is simple, but breaks easily with GUI changes
• Click tests are simple, but annoying. A lot of documentation changes are needed after GUI changes
• Programmatic approach needs developers to define tests, but is much more robust against changes
26
2
Stephan J. Schmidt, cintoo
Testing with Jemmy
• Jemmy is a windows driver
• Provides operators like JButtonOperator
• Test: Find component then drive component through operator then check for result/ state
27
Jemmy
SwingView
MockEditor
Test
click /ok
ok
Stephan J. Schmidt, cintoo
Testing the Swing view
28
Mock mockEditor = mock(CalcEditor.class);mockEditor.expects(once()).method("calculate");...JTextFieldOperator aField = new JTextFieldOperator(main, name("a"));...JButtonOperator calculateButton = new JButtonOperator(main);
aField.enterText("2");bField.enterText("3");
calculateButton.doClick();
assertEquals(sumField.getText(), 5);
Findcomponent
Drivecomponent
Checkresults
Stephan J. Schmidt, cintoo
Database layer
• Store all calculations
• Relational database management system
29
a b sum
Calculations
a b sum
2 3 5
Calculations
3
add()
Stephan J. Schmidt, cintoo
Testing the database layer
• Use in-memory database
• Free utilities exist to check results in database
30
JDBCCalcStorage
Test
set / ok
ok InMemory
Stephan J. Schmidt, cintoo
Writing and checking data
• write data to database then check data in database
• use helper methods like rowCount
31
CalcStorage storage = new JdbcCalcStorage(config);
storage.store(2, 3, 5);
assertEquals( "One row has been added", 1, rowCount("Calculations"));
assertEquals("Correct data has been written", 1, rowCount("Calculations", "a=2 AND b=3 AND sum=5"));
Stephan J. Schmidt, cintoo
In-Memory Database configuration with HSQL
• HSQL in memory database,
automatically knows “sa” user
• automatically creates database
• hsql.jar with driver, all inclusive
• Create and drop tables in setUp and tearDown
32
Config config = new Config( "sa", "", "jdbc:hsqldb:mem:testdb", "org.hsqldb.jdbcDriver");
Stephan J. Schmidt, cintoo
Also test O/R Mappers
• Even with Hibernate, ... use unit tests
• Are you sure your configuration does cascading delete correctly?
• Do the queries return the correct objects?
• Are all those foreign key relationships managed?
• For big project probably only test important key parts
33
Stephan J. Schmidt, cintoo
Coverage
• Code is instrumented by coverage tool
• Find code which is not executed during tests
• Statements, methods, conditionals
• Help QA to understand your tests
34
Stephan J. Schmidt, cintoo
100% Test Coverage
• Not faked :-)
• Filter main and Exceptions away (not your own!)
• Possible but usually not needed
• May distract developers from real goals
35
Stephan J. Schmidt, cintoo
Credits
• Thanks to Zutubi for Pulse integration server
• Thanks to cenqua for Clover code coverage
• Thanks to Cedric for TestNG, Kent and Martin for JUnit
• Thanks to the creators of the other tools
• Tools used: IDEA, jMock, Pulse, Clover, Jemmy, TestNG/ JUnit, HSQL
36
Stephan J. Schmidt, cintoo
References
• Kent Beck, “The Future of Developer Testing”, SDForum 2004
• David Astels, “test-driven development - A Practical Guide”, 2003
• Steve Freeman, Nat Pryce, Tim Mackinnon, Joe Walnes, “Mock Roles, not Objects”
37
Stephan J. Schmidt
cintoo lead developerhttp://[email protected]