unit testing
DESCRIPTION
Unit Testing. Topics. Motivation JUnit framework Basic JUnit tests – static methods @Before and @BeforeClass – instance methods Ensure exceptions thrown Test floating point values. Test-Driven Development (TDD). Add a test (or tests) for an new unit of functionality (unit === method) - PowerPoint PPT PresentationTRANSCRIPT
Unit TestingUnit Testing
TopicsTopics
• Motivation• JUnit framework• Basic JUnit tests – static methods• Ensure exceptions thrown• @Before and @BeforeClass –
instance methods• Test floating point values
JUnit MotivationJUnit Motivation• Goal: relieve human from task of comparing
expected and actual values
public class Utilities {public static int calcPerimeter(int length, int width)
{ return 2 * (length + width); }
public static void main(String [] args) { // Ensure output is 16 System.out.println(Utilities.calcPerimeter(2,6)); }
}
Test-Driven Development (TDD)Test-Driven Development (TDD)
1. Add a test (or tests) for an new unit of functionality (unit === method)
2. Run prior tests, see new test fail– may write stubs so code compiles
3. Implement new functionality4. Run tests, see them succeed5. Refactor – clean code rocks!6. Repeat
Tests FirstTests First
• Some “easy” examples– How would you test a function to
calculate the area of a triangle?– How would you test a function to
calculate the circumference of a circle?– How would you test a function that
calculates wind chill?
JUnit FrameworkJUnit Framework• Test Case. Method that runs one or more
tests. • Test Suite. Collection of tests run at the
same time. Includes one or more test cases/methods.
• Test Runner. Utility used to run a test suite. – In Eclipse, shows a graphical presentation. – May also be a command-line version (Ruby).
• JUnit framework available from http://junit.org
Packages in JavaPackages in Java
• A package is a way to bundle classes by functionality
Customers don’t really want to see all your test code!
Create a PackageCreate a Package
In Eclipse:• Create a Java project, click on src• Select new package icon• Enter an appropriate name• For this example, create a package
named windchill*• Select the package, create a new
class named MyTempConverter
* for distribution, you’d want to ensure uniquehttp://www.efsavage.com/blog/posts/java_package_conventions/
More on PackagesMore on Packages
• The package statement must be the first line in the file, e.g.:package windchill;
public class MyTempConverter {
…
}
• Each package has its own directory (in the file structure)
TDD Example: WindchillTDD Example: Windchill
See the formula and chart:http://www.nws.noaa.gov/om/windchill/index.shtml
Windchill formula:• 35.74 + 0.6215T - 35.75V (**0.16) + 0.4275TV(**0.16)
The TempConverter classThe TempConverter class
• First we create the “failing” methods – so that our tests will at least compile
package windchill;
public class MyTempConverter {
public static long windChill(int speed, int temperature){ return -1;}
}
Why does it make sense for this method to be static?
Adding the testsAdding the tests
• Create a package for your tests• Add your test classes to the package
– Select the test package– Create a new class of type JUnit Test
Case
Eclipse and JUnitEclipse and JUnit
1. Select JUnit Test Case 2. Select JUnit Test Case
We’ll use JUnit 4Pick a meaningful name
click
Eclipse and JUnit continuedEclipse and JUnit continued
Dialog for class to test:You must type in packageThen you’ll see possible classes
Eclipse prompts for libraryEclipse prompts for library
Build PathBuild PathIf Eclipse creates a JUnit test for you, you’ll be prompted to add library.To add a library later:
Right-click on project name (in package explorer)Select Build PathSelect Add Libraries
Select JUnit 4
JUnit v4JUnit v4
• New Java Feature: annotations• Places a “marker” in code that is
interpreted by another tool• For JUnit, marker/annotation is @Test• No need to extend TestCase (JUnit3)• Must import org.junit.*;
Some windchill testsSome windchill testspackage tests;
import junit.framework.Assert;
import static org.junit.Assert.*;
import Windchill.MyTempConverter;
public class TestWindchillCalcs {
@Test
public void testWindchill()
{
long expected = -11;
long actual = MyTempConverter.windChill(5, 0);
assertEquals(expected, actual);
// local variables not needed
assertEquals(3, MyTempConverter.windChill(10, 15));}
}
The TempConverter classThe TempConverter class
• Now add code so that the tests pass
package Windchill;
public class MyTempConverter {
public static long windChill(int speed, int temperature){ double newTemp = 35.74 + 0.6215*temperature - 35.75 * Math.pow(speed, 0.16) + 0.4275 * temperature * Math.pow(speed,0.16); return Math.round(newTemp);}
public static void main(String[] args) { System.out.println(MyTempConverter.windChill(10, 30));
}
}
Run as JUnit TestRun as JUnit Test
JUnit ExecutionJUnit Execution
All is well!
Error! Look at failure trace for explanation
Can also test for expected exceptionsCan also test for expected exceptionspackage Windchill;
public class BadInputException extends RuntimeException {public BadInputException() {}
public BadInputException(String msg){ super(msg); }}
@Test (expected = BadInputException.class)public void testWindchillLowSpeed() throws BadInputException{ long actual = MyTempConverter.windChill(4, 10);}
public static long windChill(int speed, int temperature){if (speed < 5) throw new BadInputException("Windchill not valid if speed < 5");double newTemp = 35.74 + 0.6215*temperature - 35.75 * Math.pow(speed, 0.16) + 0.4275 * temperature * Math.pow(speed,0.16);return Math.round(newTemp);}
Exception class
JUnit test
Discuss with a partnerDiscuss with a partner
• When would we need the throws clause on the test?
• What happens if the (expected) phrase is removed?
Testing instance methodsTesting instance methods• When testing a class that has instance methods
(most often), the test will need to create an instance
• @BeforeClass and @AfterClass annotated methods will be run exactly once during your test run - at the very beginning and end of the test as a whole, before anything else is run. In fact, they're run before the test class is even constructed, which is why they must be declared static.
• The @Before and @After methods will be run before and after every test case, so will probably be run multiple times during a test run
Example to illlustrate @BeforeExample to illlustrate @Before
package game;
public class Location {
private int x, y;
public void move(int dx, int dy)
{
x += dx;
y += dy;
}
// Also has constructors and getters
}
Test it – see @Before messageTest it – see @Before messagepublic class TestLocation {
private Location location;
@Before
public void setUp(){
System.out.println("In @Before"); location = new Location();
}
@Test
public void testMove() {
location.move(5, 10);
assertEquals(5, location.getX());
assertEquals(10, location.getY());
}
@Test
public void testMove2() {
location.move(5, 10);
assertEquals(5, location.getX());
assertEquals(10, location.getY());
location.move(5, 10);
assertEquals(10, location.getX());
assertEquals(20, location.getY());
}
}
Example of @BeforeClassExample of @BeforeClass• Assume the board set up is complex, and
you don’t need to reset between tests.
package game;
public class Board { private String gameStatus;
public void init() { gameStatus = "Long game set up is done!"; } public String getGameStatus() { return gameStatus; }
}
The @BeforeClass testThe @BeforeClass testimport game.Board;
public class TestBoard {
static Board board;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("In @BeforeClass");
board = new Board();
board.init();
}
@Test
public void test1() {
assertEquals(board.getGameStatus(), "Long game set up is done!");
}
@Test
public void test2() {
assertEquals(board.getGameStatus(), "Long game set up is done!");
}
}
}
@BeforeClass not run for each test instance – just the entire test suite – so variables must be static
This is an advanced detail – will not be covered on tests, BUT may be helpful in your projects
Testing floating pointsTesting floating points• Remember that floating point values should not be
compared exactly. public class MyConverter {
public static double INCHES_TO_METERS = 0.0254;
public static double englishToMeters(int feet, int
inches)
{
return 0;
//int totalInches = feet * 12 + inches;
//return totalInches * INCHES_TO_METERS;
}
}
The testThe test• Use a tolerance
public class TestConversions {
public static double EPSILON = .0001;
@Test
public void testFeetToMeters()
{
double expected = 0.0508;
double actual = MyConverter.englishToMeters(0, 2);
assertEquals(expected, actual, EPSILON);
expected = 0.3556;
actual = MyConverter.englishToMeters(1, 2);
assertEquals(expected, actual, EPSILON);
}
What tests could you write for…What tests could you write for…
• A chess game• A linked list library• String library• UPC code
Advanced TopicAdvanced Topic• The static import construct allows unqualified access to static members
import static org.junit.Assert.assertEquals;
@Test
public void testMove3() {
location.move(5, 10);
assertEquals(5, location.getX());
assertEquals(10, location.getY());
}