1. Developer Testing
Achieving a hundred percent test coverage for database and Swing applications
Stephan J. Schmidt
cintoo lead developer
http://cintoo.org
stephan@cintoo.org
2. 2
Contents
• What is developer testing
• Why you should practice developer testing
• How you can do developer testing
• How to test nasty things
Stephan J. Schmidt, cintoo
3. 3
What is Developer Testing
Simple:
Testing done by developers
Stephan J. Schmidt, cintoo
4. 4
Acceptance versus Developer Tests
Acceptence Developer
Testing Testing
Tests: System against
Requirements
Code against
Design
Stephan J. Schmidt, cintoo
5. 5
Why?
• Improves the health of your system
• Gives you a good feeling
• Makes you more confident
• Developer testing makes you more effective
Stephan J. Schmidt, cintoo
6. 6
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
Stephan J. Schmidt, cintoo
7. 7
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
Stephan J. Schmidt, cintoo
8. 8
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)
Stephan J. Schmidt, cintoo
9. 9
Example adding two numbers
public class Math {
public static int add(int a, int b) {
return a + b;
}
}
Stephan J. Schmidt, cintoo
10. 10
Testing Math with an Unit Test
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
11. 11
Test tools
• Tests are run with
a testing tool
• Tool displays non-
working tests
Stephan J. Schmidt, cintoo
12. 12
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)
Stephan J. Schmidt, cintoo
13. 13
Example application SuperAdd
• Will replace Excel!
• Adding two numbers
• Graphical user interface for data entry
• Storing the calculations in a database
Stephan J. Schmidt, cintoo
14. 14
Architecture
• Three tier application GUI
• Different testing
scenarios for every Logic
tier
Storage
Stephan J. Schmidt, cintoo
15. 15
Architecture
Buttons
Application Border SwingCalcView
State
CalcView
GUI 2
CalcEditor
1 Logic Math CalcManager
3
CalcStorage
Storage
JDBCCalcStorage
Application Border State
DB
Stephan J. Schmidt, cintoo
16. 16
Testing SuperAdd
• Test Logic (Math, CalcManager) easy
• Test Storage (JDBCCalcStorage) not so easy
• Test GUI (CalcView, CalcEditor) hmm. some thinking needed
Stephan J. Schmidt, cintoo
17. 17
Testing Math is easy 1
calculate / ok
Test Math
• Already shown, lucky me :-)
• Test for negative numbers, overflow, ...
Stephan J. Schmidt, cintoo
18. 18
Testing CalcManager 1
set / ok
CalcManager
Test
ok MockCalcStorage
• 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
Stephan J. Schmidt, cintoo
19. 19
Mock objects
Test
• In-replacement for objects
• Mocks simulate the
dependencies Class to Test
• Testing in isolation
• Testing classes "from below" Dependencies
as Mocks
Stephan J. Schmidt, cintoo
21. 21
Usually Java GUIs look like this
public class View {
...
calculateButton.addActionListener(
...
sumField.setText(
Math.add(
aField.getText(),
bField.getText());
));
}
Hard to test, depends on
}
Swing. Logic not reusable
in different GUI frameworks!
Stephan J. Schmidt, cintoo
22. 22
GUI splitting
• View/Editor pattern, split GUI in view and editor
• Remove ALL logic from the view
• Editor contains the logic
View
GUI
Editor
Stephan J. Schmidt, cintoo
23. 23
View
public class View {
...
calculateButton.addActionListener(
...
editor.calculate()
));
}
public void setSum(int sum) {
sumField.setText(sum);
}
}
Stephan J. Schmidt, cintoo
24. 24
Editor
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
25. 25
Editor Test
@Test
public 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
26. 26
GUI Testing 2
• 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
Stephan J. Schmidt, cintoo
27. 27
Testing with Jemmy
Jemmy
click /
ok
Test SwingView
ok
MockEditor
• Jemmy is a windows driver
• Provides operators like JButtonOperator
• Test: Find component then drive component through
operator then check for result/ state
Stephan J. Schmidt, cintoo
28. 28
Testing the Swing view
Mock mockEditor = mock(CalcEditor.class);
mockEditor.expects(once()).method("calculate");
Find ...
JTextFieldOperator aField =
component new JTextFieldOperator(main, name("a"));
...
JButtonOperator calculateButton =
new JButtonOperator(main);
aField.enterText("2");
Drive bField.enterText("3");
component
calculateButton.doClick();
assertEquals(sumField.getText(), 5);
Check
results
Stephan J. Schmidt, cintoo
29. 29
Database layer 3
• Store all calculations
• Relational database management system
Calculations Calculations
add()
a b sum a b sum
2 3 5
Stephan J. Schmidt, cintoo
30. 30
Testing the database layer
set / ok
JDBCCalcStorage
Test
ok In
Memory
• Use in-memory database
• Free utilities exist to check results in database
Stephan J. Schmidt, cintoo
31. 31
Writing and checking data
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"));
• write data to database then check data in database
• use helper methods like rowCount
Stephan J. Schmidt, cintoo
32. 32
In-Memory Database configuration with HSQL
Config config = new Config(
"sa",
"",
"jdbc:hsqldb:mem:testdb",
"org.hsqldb.jdbcDriver");
• 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
Stephan J. Schmidt, cintoo
33. 33
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
Stephan J. Schmidt, cintoo
34. 34
Coverage
• Code is
instrumented by
coverage tool
• Find code which
is not executed
during tests
• Statements,
methods,
conditionals
• Help QA to
understand your
tests
Stephan J. Schmidt, cintoo
35. 35
100% Test Coverage
• Not faked :-)
• Filter main and Exceptions away (not your own!)
• Possible but usually not needed
• May distract developers from real goals
Stephan J. Schmidt, cintoo
36. 36
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
Stephan J. Schmidt, cintoo
37. 37
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”
Stephan J. Schmidt, cintoo