Unit Testing Tutorial Fall 12 CSC 2053 Testing Tools: JUNIT - Various Examples Automated testing using the JUnit class is the tool most developers use. NetBeans makes it easy as does Eclipse. We will discuss testing in terms of NetBeans and setting simple tests on your own. Basically, when you create your classes this testing should be set up because going back later Is a major problem with a large project. Part One -Writing Your Own Assertions When implementing and debugging a class, it is useful to state conditions that should be true at a particular point in a method. These conditions, called assertions, ensure a program’s validity by catching potential bugs and identifying possible logic errors during development. Preconditions and postconditions are two types of assertions. Preconditions are assertions about a program’s state when a method is invoked, and post -conditions are assertions about a program’s state after a method finishes. Java includes two versions of the assert statement for validating assertions programmatically. The assert statement evaluates a boolean expression and determines whether it is true or false. The first form of the assert statement is assert expression; This statement evaluates expression and throws an AssertionError if the expression is false. The second form is assert expression1 : expression2; This statement evaluates expression1 and throws an AssertionError with expression2 as the error message if expression1 is false. You can use assertions to programmatically implement preconditions and post-conditions or to ensure your code is working correctly. The example belowdemonstrates the functionality of the assert statement. Line 11 prompts the user to enter a number between 0 and 10, then line 12 reads the number from the command line. The assert statement on line 15 determines whether the user entered a number within the valid range. If the user entered a number that is out of range, then the program reports an error. Otherwise, the program proceeds normally 1 Unit Testing Tutorial Fall 12 CSC 2053 AssertTest.java // Uses assert to check that an absolute value is positive import java.util.Scanner; public class AssertTest { public static void main( String args[] ) { Scanner input = new Scanner( System.in ); System.out.print( "Enter a number between 0 and 10: " ); int number = input.nextInt(); // assert that the absolute value is >= 0 assert ( number >= 0 && number <= 10 ) : "bad number: " + number; System.out.printf( "You entered %d\n", number ); } // end main } // end class AssertTest Enter a number between 0 and 10: 5 You entered 5 Enter a number between 0 and 10: 50 Exception in thread "main" java.lang.AssertionError: bad number: 50 at AssertTest.main(AssertTest.java:15) Assertions are primarily used by the programmer for debugging and identifying logic errors in an application. By default, assertions are disabled when executing a program because they reduce performance and are unnecessary for the program’s user. (See instruction below for running AssertTest from the command prompt and in JGrasp (easiest)) To enable assertions at runtime from the command prompt, use the -ea command-line option with a java command. To execute the above program with assertions enabled: First Save your file AssertTest.java to your main c:\ folder Find and open the command prompt (see below for instructions) To run the program, enter javac AssertTest.java java -ea AssertTest // compiles the class // runs the class with assertions enabled 2 Unit Testing Tutorial Fall 12 CSC 2053 How to run the ea command from the command prompt: When you click on the start menu , you should have a link to the “command prompt” somewhere at the top of the menu or else look for it in a sub menu. Find it and click on it When you click on the command prompt, a window appears with a black background And you will be in the main c: folder. If the prompt opens in another folder e.g. c:\ users\Cathy Just use the command cd c:\ cd means change directory and this command will put you in the c:\ folder To make it easy, just save your AssertTest file in the c: folder and so you do not have to navigate to another location - if this does not work, put the file in the bin folder of the JDK (You could navigate to the folder where your java file is if you do not want to put in the main c: folder - to do this you use: cd: path where path is the location where your java file is. ) In the c: folder, type in the line below when to run your test. (Your java file AssertTest should be in the c:\ folder or else you need to navigate to where it is.) c:\ javac AssertTest.java c:\ java -ea AssertTest // compiles it // runs it with assertions enabled Your output should ask you for a number. Enter an invalid number, say 80 You will get an exception that there is an assertion error You should not have any AssertionErrors through normal execution of a properly written program. Such errors should only indicate bugs in the implementation. As a result, you should never catch an AssertionError. Rather, you should allow the program to terminate when the error occurs, so you can see the error message, then you should locate and fix the source of the problem. Since application users can choose not to enable assertions at runtime, you should not use the assert statement to indicate runtime problems in production code. Rather, you should use the exception blocks to catch errors. 3 Unit Testing Tutorial Fall 12 CSC 2053 How To Enable Assertions for Java Programs in JGrasp First you have to create a project and put AssertTest class in it To pass "-ea" to the JVM you need to add it to the Run flags in the compiler settings. Go to Settings ->Compiler Settings > Workspace. Select language "Java" if not already selected. Select the Flags/Args/Main tab. On the row Run and column FLAGS2 or ARGS2, click OFF the black square (this allows you to enter values), and enter "-ea", then OK the dialog. Note that FLAGS or ARGS are for your program, and FLAGS2 or ARGS2 are for the JVM. You can run the AssertTest from JGrasp. You should also be able to run the unit test below. PART TWO - Unit testing with JUnit A unit test is a piece of code written by a developer that executes a specific functionality in the code under test. Unit tests ensure that code is working as intended and validates that this is still the case after code changes. JUnit 4.x is a test framework which uses annotations to identify methods that are test methods. JUnit assumes that all test methods can be executed in an arbitrary order. Therefore Writing Tests - How do I write and run a simple test? ( This is using JUnit and command line) To write a test with JUnit – Doing it this way is really tricky. Annotate a method with @org.junit.Test Use a method provided by JUnit to check the expected result of the code execution versus the actual result You have to first download JUnit and install it to do this Writing Tests 1. How do I write and run a simple test? You can set up JUnit in JGrasp, but you will have configure to get it to run or you can run from the command line in which case you have to give the full classpath for the installed JUnit 4 Unit Testing Tutorial Fall 12 CSC 2053 In Jgrasp you need to set the classpath with classpath=%classpath%;INSTALL_DIR\junit-4.11.jar;INSTALL_DIR1 where INSTALL_DIR is the name of the folder where you put the .jar file you downloaded to install JUnit and INSTALL_DIR1 – is the name of the folder where JUnit is stored Create a class to Test: //package junitfaq;//optional if not in JGrasp import org.junit.*; import static org.junit.Assert.*; import java.util.*; public class SimpleTest { //Write a test method (annotated with @Test) that asserts expected results on the //object under test: @Test or @org.junit.Test public void testEmptyCollection() { Collection collection = new ArrayList(); assertTrue(collection.isEmpty()); } //Although writing a main() method to run the test is much less important with the advent //of IDE runners, it's still possible: public static void main(String args[]) { org.junit.runner.JUnitCore.main("junitfaq.SimpleTest"); } } 1. Run the test: To run the test from the console, type: java org.junit.runner.JUnitCore junitfaq.SimpleTest To run the test with the test runner used in main(), type: javac SimpleTest.java java SimpleTest // if not in a package 2. The passing test results in the following textual output: . Time: 0 OK (1 tests) 5 Unit Testing Tutorial Fall 12 CSC 2053 To Run the test from the command prompt: You must be in folder where the class is located or if you are in C:|\ include the PATH where it is located See instruction above in part one for running a program from the command prompt Note: to make this easy , save your file to the c:\ folder a) To run the test from the command prompt, navigate to folder where the above file is and type: C:\ :{path to where the class is located} javac SimpleTest.java // compile it and then run it Run it: c:\{path to where the class is located} java org.junit.runner.JUnitCore junitfaq.SimpleTest OR: b) To run the test with the test runner used in main() method in the SimpleTest class, type: {PATH}java junitfaq.SimpleTest The passing test results in the following textual output: Time: 0 OK (1 tests) This process is tricky so running if from an editor where Unit is already stored is preferable. PART THREE - Using JUnit In Eclipse 1. To write a test with JUnit you must: Annotate a method with @org.junit.Test Use a method provided by JUnit to check the expected result of the code execution versus the actual result You can use Eclipse or the org.junit.runner.JUnitCore class to run the test. (See above) 2. Installation of JUnit If you use Eclipse you can use the integrated JUnit in Eclipse for your testing. 3. Preparation: a) Create a new java project. We want to create the unit tests in a separate folder so when creating a new project do the following. First Create a new source folder test that will be on the same level as the src folder 6 Unit Testing Tutorial Fall 12 CSC 2053 a) Choose file New->java project b) when the next window comes up, enter the project name e.g “UnitTest” c) press next, and d) under the source tab on the next screen , at the bottom of the screen choose d) Create new Folder-> and enter “test” for the folder name e) Also under Source tab - select, “Add project(project name e.g. UnitTest) to BuildPath UnitTest/src UnitTest/bin Your folder hierarchy should now have two folders under the project name src and test. 7 Unit Testing Tutorial Fall 12 CSC 2053 Inside the src folder, you want to create a package e.g. testunit To create the package right click on src inside your project folder and choose New ->package Enter name of package e.g. testunit Testunit package should appear inside the src folder(if you can read that below 4. Create a Java class to be tested: Right click on the package folder you made above and choose new->file When you create the file , choose options to generate comments etc. put this code into the new file package testunit; /** * @author Cathy * */ public class MyClass { public int multiply(int x, int y) { return (x * y); } } 8 Unit Testing Tutorial Fall 12 CSC 2053 5. NOW Create a JUnit test Right click on MyClass.java in the Package Explorer and select New → JUnit Test Case. Select "New JUnit 4 test" and ***set the source folder to test as below, so that your test classes gets created in this folder. UnitTest/test use name of project testunit use Package name - testunit.MyClass // use package and class 9 Unit Testing Tutorial Fall 12 CSC 2053 Press the Next button and select the methods which you want to test. You only have one. If no methods show up, there is something wrong with how you set up the package and the class it contains. Make sure you have the class you are going to test inside the package and have a separate test folder 10 Unit Testing Tutorial Fall 12 CSC 2053 If the JUnit library in not part of your class path, Eclipse will prompt you to do so. 11 Unit Testing Tutorial Fall 12 CSC 2053 Now, Create a test class in the test folder(not src) with the following code. package testunit; // this is name of package in the test folder also import static org.junit.Assert.*; import org.junit.Test; public class MyClassTest { @Test public void test() { MyClass tester = new MyClass(); System.out.println("I am in tester "); assertEquals("Result", 50, tester.multiply(10, 5)); } } 6. Run your test via Eclipse Right click on your new test class and select Run-As → JUnit Test. The result of the tests will be displayed in the JUnit View. testunit.MyClassTest testMultiply(0.015 s) The test should be successful (indicated via a green bar). If it is not working correctly you get a red bar as above JUnit is easier to set up and run in NetBeans. To set a suite of classes to run, see Part 5 12 Unit Testing Tutorial Fall 12 CSC 2053 PART 4 – Junit types of annotations Annotations The following table gives an overview of the available annotations in JUnit 4.x. Table 1. Annotations Annotation Description @Test public void method() The annotation @Test identifies that a method is a test method. @Before public void method() Will execute the method before each test. This method can prepare the test environment (e.g. read input data, initialize the class). @After public void method() Will execute the method after each test. This method can clean up the test environment (e.g. delete temporary data, restore defaults). @BeforeClass public void method() Will execute the method once, before the start of all tests. This can be used to perform time intensive activities, for example to connect to a database. @AfterClass public void method() Will execute the method once, after all tests have finished. This can be used to perform clean-up activities, for example to disconnect from a database. @Ignore Will ignore the test method. This is useful when the underlying code has been changed and the test case has not yet been adapted. Or if the execution time of this test is too long to be included. @Test (expected = Exception.class) Fails, if the method does not throw the named exception. @Test(timeout=100) Fails, if the method takes longer than 100 milliseconds. Assert statements - The following table gives an overview of the available assert statements. Table 2. Test methods Statement Description fail(String) Let the method fail. Might be used to check that a certain part of the code is not reached. Or to have failing test before the test code is implemented. assertTrue(true) / assertTrue(false) Will always be true / false. Can be used to predefine a test result, if the test is not yet implemented. assertTrue([message], boolean condition) Checks that the boolean condition is true. assertsEquals([String message], Tests that two values are the same. Note: for arrays the 13 Unit Testing Tutorial Fall 12 CSC 2053 Statement Description expected, actual) reference is checked not the content of the arrays. assertsEquals([String message], expected, actual, tolerance) Test that float or double values match. The tolerance is the number of decimals which must be the same. assertNull([message], object) Checks that the object is null. assertNotNull([message], object) Checks that the object is not null. assertSame([String], expected, actual) Checks that both variables refer to the same object. assertNotSame([String], expected, actual) Checks that both variables refer to different objects. Part 5 - Test Suites: If you have several tests you can combine them into a test suite. Running a test suite will execute all tests in that suite. To create a test suite: a) Select your test classes → right click on it → New → Other → JUnit → Test Suite. b) Select the Next button and select the methods for which you want to create a test. Change the code to the following to make your test suite run your test. 14 Unit Testing Tutorial Fall 12 CSC 2053 If you develop another test later you can add it to @Suite.SuiteClasses. package mypackage; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ MyClassTest.class }) public class AllTests { } Run your test via code You can also run your tests from via your own code. The org.junit.runner.JUnitCore class provides the runClasses() method which allows you to run one or several tests classes. As a return parameter you receive an object of the type org.junit.runner.Result. This object can be used to retrieve information about the tests. In your test folder create a new class MyTestRunner with the following code. This class will execute your test class and write potential failures to the console. package de.vogella.junit.first; import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; public class MyTestRunner { public static void main(String[] args) { Result result = JUnitCore.runClasses(MyClassTest.class); for (Failure failure : result.getFailures()) { System.out.println(failure.toString()); } } } Static imports with Eclipse JUnit uses a lot of static methods and Eclipse cannot always correctly automatically import static imports. You can make the JUnit test methods available via the content assists. Open the Preferences via Window → Preferences and select Java → Editor → Content Assist → Favorites. 15 Unit Testing Tutorial Fall 12 CSC 2053 Use the new "New Member" button to add the methods you need. The example below makes the assertTrue, assertFalse and assertEquals methods available. You can now use Content Assist (Ctrl+Space) to add the method and the import. Add at least the following new members: org.junit.Assert.assertTrue org.junit.Assert.assertFalse org.junit.Assert.assertEquals org.junit.Assert.fail PART 4 - USING NETBEANS TO CREATE UNIT TESTS NetBeans provides the facility to create a test suite of testing classes for your project. It is automated and once you have set up the Unit Tests you can use them to check your program frequently. This is particularly useful when you are refactoring and changing code; Step One – setting up the test classes 1. In NetBeans, load a project into the project window. (If you already have a developed project in NetBeans, go to Step Two) 2. You can create a new application by first setting up a directory for your project and then go to: File, new Project, Under Categories, Choose java And the choose Java Application 3. Then in the next screen specify the directory where your files will stored – this should be the same directory you created in step two above. . This will also be the name of the project 16 Unit Testing Tutorial Fall 12 CSC 2053 Choose Finish and a class with main method will appear in the right hand screen. Then Choose File, New File from the top menu bar and select java, java class as below Give the file a name 17 Unit Testing Tutorial Fall 12 CSC 2053 And click finish. A main method will have already appeared in the right hand screen. Copy and paste the code from the main method I send you into that. Copy and paste the code from the DatingService class I sent into the new file. *************************************************************************** 4. Generated tests are distinguished by appending Test to the tested classes' names (e.g. DatingServiceTest.java). To create a test, the project must have a test directory for the tests. The IDE creates a Test Packages directory by default when you create a project from scratch. The next three steps deal with Creating Test Packages when you have created a project from existing files - skip this as we are doing it from scratch and go to Step Two. 4. If no test directory exists in your project or you want to specify a different directory for your test, you can specify a test directory in the project properties dialog box. 5. Right click on main project folder in the window to the left of the Files window and choose properties (last option on drop down list) and a properties screen comes up. 6.On the second window space for entering data labeled Test package folder, click add folder and use the same path as you used to set up original projects: e.g. C:\CFILES\COURSES\2053\JUnit\dictionary The folder should appear in the window and you can click o.k. 18 Unit Testing Tutorial Fall 12 CSC 2053 Step Two To Create a test for a single existing class choose Files from the tabs in the left window below to view your files: Method 1 To create a test for a single class: Right-click the class in the Projects window – navigate to the source files of the project to find the file and right-click on it Choose Tools > Create JUnit Tests (Ctrl-Shift-U) to open the Create Tests dialog box. 19 Unit Testing Tutorial Fall 12 CSC 2053 Select the desired code generation options and click OK. By selecting javadoc comments it will generate javadoc comments in the test class To create a test suite: Skip for Now and go to Step Three 1. Right-click the package node containing the source files for which you want to generate the test suite in the Projects window and choose Tools > Create JUnit Tests (Ctrl-Shift-U) from the popup menu. 2. Select the Generate Test Suites checkbox. 3. Select the desired code generation options and click OK. The IDE generates test classes for all enclosed classes and stores them in the project's Test Packages node. If any of the test classes already exist, those classes are updated. By default the IDE includes all the test classes as part of the generated test suite. You can also create test suites by using the New File wizard and selecting Test Suite in the JUnit category. Step Three: To run a test for a single class: 1. Select the file you just created a test for - (the class for which you want to run a test)in Projects window – navigate to the source files in the Files tab as below. 20 Unit Testing Tutorial Fall 12 CSC 2053 2. From the main menu, choose Run > Test File(Ctrl-F6). VERY IMPORTANT : Check your test file and take out any default “fail” statements on methods that have to do with “prototype. To run tests for an entire project: 1. From the main menu, in the Files Tab of the left window choose the project folder and choose Run > Test project_name (Alt-F6). The IDE executes all of the project's tests. Working with JUnit Test Output When you run a test, the IDE shows the test results in two tabs in the JUnit Test Results window: A summary of the passed and failed tests and the description of failed tests are displayed in the left pane of the console (output )window. Click the filter button to switch between viewing all test results and viewing only the failed tests. The textual output from the JUnit tests themselves is displayed in the right pane of the window. The output from the test is displayed in the Output window. Double-click any error to jump to the line in the code where the error occurred. Running JUNit in Eclipse - see: http://www.vogella.com/articles/JUnit/article.html 21 Unit Testing Tutorial Fall 12 CSC 2053 Go to this link for details on how set up tests: http://junit.sourceforge.net/doc/cookbook/cookbook.htm - or see below 22