Upload
fernando-brito-e-abreu
View
636
Download
1
Embed Size (px)
Citation preview
Software Testing - Test Driven Development
(TDD) with JUnit -
Fernando Brito e Abreu
DCTI / ISCTE-IUL QUASAR Research Group
Software Engineering / Fernando Brito e Abreu 2 27-Sep-11
SWEBOK: the 10 Knowledge Areas
Software Requirements
Software Design
Software Construction
Software Testing
Software Maintenance
Software Configuration Management
Software Engineering Management
Software Engineering Process
Software Engineering Tools and Methods
Software Quality
Working test first / TDD
Traditionally, code has been written using a
test-last philosophy, i.e. design, code, then test
Testing after the fact is often boring
Write code “test first” instead:
Write a simple test (one assertion)
Write enough code to make the test pass
Repeat the process, ‘filling’ out the code
Software Engineering / Fernando Brito e Abreu 3 27-Sep-11
Unit testing, extreme style
Tests should be an integral part of the coding process
Whenever you implement a class, also make a companion test class
Tests are executable documentation
Tests allow other programmers see how to use code
Therefore they are part of the specification
Software Engineering / Fernando Brito e Abreu 4 27-Sep-11
Best practices
Test everything that could possibly break
This is an XP maxim and it holds
A well-written test is hard to pass
If all your tests pass the first time, you are probably
not testing vigorously enough
All tests should pass before any update is made
to a collective code base
Software Engineering / Fernando Brito e Abreu 5 27-Sep-11
Best practices
When a test case fails, track down the problem
by writing more tests, before going to the
debugger
The more tests you have, the better
Test invalid parameters to every method, rather
than just valid data
Robust software needs to recognize and handle
invalid data, and the tests that pass using incorrect
data are often the most informative Software Engineering / Fernando Brito e Abreu 6 27-Sep-11
The xUnit testing frameworks story
Kent Beck published a unit test framework for the
Smalltalk language in 1999 named SmalltalkUnit (aka
SUnit)
Later, Erich Gamma ported SUnit to Java, creating JUnit
Many more xUnit implementations adapted to various
languages and platforms were made since
CppUnit (C++), NUnit (.Net), Dunit (Delphi), VBUnit (Visual
Basic), RUnit (R), PyUnit (Pyton), HtmlUnit, XMLUnit, …
Software Engineering / Fernando Brito e Abreu 7 27-Sep-11
JUnit for Eclipse
Test class
This bar is only green
when all tests pass!
Software Engineering / Fernando Brito e Abreu 8 27-Sep-11
Test error messages and
tracing info appear here
for the selected test case
Building a test suite
A test suite is the union of the test cases for all classes
in the system
A test suite should have:
One test class for each class in the system
Each test class should have at least one test method
(aka test case) for each method in the class under test
To be more precise, we should have a number of test cases
given by the McCabe complexity metric of the target method
Software Engineering / Fernando Brito e Abreu 9 27-Sep-11
Test case stubs
JUnit test case stubs can be generated with Eclipse
Since only one test case stub is generated per method, you
should cut and paste those stubs if McCabe complexity metric
is greater than one
Method stubs look like this:
@Test
public final void testSomeMethod()
{
fail("Not yet implemented"); // TODO
}
Software Engineering / Fernando Brito e Abreu 10 27-Sep-11
Test case stubs
Software Engineering / Fernando Brito e Abreu 11 27-Sep-11
Here we choose which
stubs we want to create
Test suite organization
Test code must be separated from application
Give them each their own unique directory tree with
the same package naming structure
One tree using “src” as root
Another tree using “tests” as root
This lets tests live in the same package as the objects
they test, while still keeping them separate during a
build
Software Engineering / Fernando Brito e Abreu 12 27-Sep-11
Test suite organization
If you select a file and do “Run As / Junit
Test” only the test cases in it are executed.
If you select a directory and do “Run As
/ Junit Test” all test classes contained in
it (recursively) are executed.
Software Engineering / Fernando Brito e Abreu 13 27-Sep-11
Naming convention
Test classes
<test class name> ::= <class name>Test
e.g. ClientAccountTest, CurrencyTest, …
Test cases
<test case name> ::= test[<n>]<method name>.java
The <n> counter can be discarded when we have a single test (McCabe
complexity = 1)
e.g. client.testgetName(), myAccount.test1deposit(),
myAccount.test2deposit(), …
This convention is just an
example. The important thing is
using a consistent convention
to facilitate maintainability.
Software Engineering / Fernando Brito e Abreu 14 27-Sep-11
JUnit mechanisms
Annotations
The mechanism by which JUnit determines organizes
and activates your test cases
Assertions
The mechanism by which JUnit determines the
success or failure of a test
An assert is a comparison between an expected
value and an actual value
Software Engineering / Fernando Brito e Abreu 15 27-Sep-11
Annotations
@BeforeClass
@AfterClass
@Before
@After
@Test
@Ignore
@Timeout
Software Engineering / Fernando Brito e Abreu 16 27-Sep-11
@BeforeClass
This annotation allows setting up methods that will run
before the full test suite contained in the class
This can be used to perform time intensive activities
Example: connect to a database
@BeforeClass
public void runBeforeFullSuite() {
// run once before all test cases
}
There is no restriction on the names of
the methods, but you should use
semantically meaningful identifiers
Software Engineering / Fernando Brito e Abreu 17 27-Sep-11
@AfterClass
This annotation allows setting up methods that will run
after all tests contained in the class have finished
This can be used to perform clean-up activities
Example: disconnect from a database
@AfterClass
public void runAfterFullSuite() {
// run for one time after all test cases
}
Software Engineering / Fernando Brito e Abreu 18 27-Sep-11
@Before
This annotation allows setting up all test cases, since the
corresponding method will run before each test case
A @Before method can prepare the test environment
e.g. read input data, initialize the class
@Before
public void runBeforeEveryTest() {
simpleMath = new SimpleMath();
}
Software Engineering / Fernando Brito e Abreu 19 27-Sep-11
@After
This annotation allows tearing down test methods since
it will run after every test case
@After
public void runAfterEveryTest() {
simpleMath = null;
}
Software Engineering / Fernando Brito e Abreu 20 27-Sep-11
@Test
Mark your test cases with @Test annotations
You don’t need to prefix your test cases with “test”,
although this is a good naming convention
@Test
public void testAddition() {
assertEquals(12, simpleMath.add(7, 5));
}
@Test
public void testSubtraction() {
assertEquals(9, simpleMath.subtract(12, 3));
}
Software Engineering / Fernando Brito e Abreu 21 27-Sep-11
@Test
Another example:
@Test
public void listEquality() {
List<Integer> expected = new ArrayList<Integer>();
expected.add(5);
List<Integer> actual = new ArrayList<Integer>();
actual.add(5);
assertEquals(expected, actual);
}
Software Engineering / Fernando Brito e Abreu 22 27-Sep-11
@Test(timeout = <delay>)
Define a timeout period in milliseconds with “timeout”
parameter
The test fails when the timeout period exceeds
@Test(timeout = 1000)
public void infinity() {
while (true)
;
}
Software Engineering / Fernando Brito e Abreu 23 27-Sep-11
@Test(expected = <exception>.class)
Tests succeeds if the method throws the exception
Notice that the fail command is not executed
because the exception is raised and caught
by JUnit, that sees any further.
Software Engineering / Fernando Brito e Abreu 24 27-Sep-11
@Ignore
Use this annotation for test cases you want to ignore
You can add a string parameter that defines the reason of
ignorance
This may be useful if the underlying code has been changed and
the test has not yet been adapted
@Ignore("Not Ready to Run")
@Test
public void multiplication() {
assertEquals(15, simpleMath.multiply(3, 5));
}
Software Engineering / Fernando Brito e Abreu 25 27-Sep-11
Assertions
assertEquals
assertEquals for arrays
assertNull / assertNotNull
assertSame / assertNotSame
assertTrue / assertFalse
fail
Software Engineering / Fernando Brito e Abreu 26 27-Sep-11
assertEquals This assertion states that:
expected.equals(actual) returns true, or
both objects are null
A message is printed if supplied, when a test fails
The equality test for a double or a float should specify
a maximum tolerance range (the delta), to cope with
floating point errors
There are overloaded versions of this method for all
Java’s primitive types
Software Engineering / Fernando Brito e Abreu 27 27-Sep-11
assertEquals(Object expected, Object actual) assertEquals(String message, Object expected, Object actual) assertEquals(Object expected, Object actual, delta) assertEquals(String message, Object expected, Object actual, delta)
assertEquals for arrays
Two arrays are equal if they have the same length and
each element is equal to the corresponding element in
the other array; otherwise, they’re not.
public static void assertEquals(Object[] expected, Object[] actual);
public static void assertEquals(String message, Object[] expected, Object[]
actual);
Software Engineering / Fernando Brito e Abreu 28 27-Sep-11
assertNull / assertNotNull This asserts that an object reference equals null,
printing a message otherwise (if supplied)
This asserts that an object reference is not null,
printing a message otherwise (if supplied)
assertNotNull(Object object),
assertNotNull(String message, Object)
assertNull(Object object),
assertNull(String message, Object object)
Software Engineering / Fernando Brito e Abreu 29 27-Sep-11
assertSame / assertNotSame Asserts that the two objects are the same, printing a
message otherwise (if supplied)
This is a stricter condition than simple equality, as it
compares the object identities using expected == actual
Asserts that the two objects are not the same,
printing a message otherwise (if supplied)
assertSame(Object expected, Object actual)
assertSame(String message, Object expected, Object actual)
assertNotSame(Object expected, Object actual)
assertNotSame(String message, Object expected, Object actual)
Software Engineering / Fernando Brito e Abreu 30 27-Sep-11
assertTrue / assertFalse Asserts that the condition is true, printing a message
otherwise (if supplied)
Asserts that the condition is false, printing a message
otherwise (if supplied)
assertTrue(boolean condition)
assertTrue(String message, boolean condition)
Software Engineering / Fernando Brito e Abreu 31 27-Sep-11
assertFalse(boolean condition)
assertFalse(String message, boolean condition)
fail
This forces a failure. This is useful to close off paths
through the code that should not be reached
fail()
fail(String message)
Software Engineering / Fernando Brito e Abreu 32 27-Sep-11
More Reading
http://www.junit.org/index.htm
http://open.ncsu.edu/se/tutorials/junit/
http://www.cs.umanitoba.ca/~eclipse/10-JUnit.pdf
http://supportweb.cs.bham.ac.uk/documentation/tutorial
s/docsystem/build/tutorials/junit/junit.pdf
http://junit.sourceforge.net/javadoc/junit/framework/
Software Engineering / Fernando Brito e Abreu 33 27-Sep-11