1 package junit.framework; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Modifier; 6 7 /** 8 * A test case defines the fixture to run multiple tests. To define a test case<br/> 9 * <ol> 10 * <li>implement a subclass of <code>TestCase</code></li> 11 * <li>define instance variables that store the state of the fixture</li> 12 * <li>initialize the fixture state by overriding {@link #setUp()}</li> 13 * <li>clean-up after a test by overriding {@link #tearDown()}.</li> 14 * </ol> 15 * Each test runs in its own fixture so there 16 * can be no side effects among test runs. 17 * Here is an example: 18 * <pre> 19 * public class MathTest extends TestCase { 20 * protected double fValue1; 21 * protected double fValue2; 22 * 23 * protected void setUp() { 24 * fValue1= 2.0; 25 * fValue2= 3.0; 26 * } 27 * } 28 * </pre> 29 * 30 * For each test implement a method which interacts 31 * with the fixture. Verify the expected results with assertions specified 32 * by calling {@link junit.framework.Assert#assertTrue(String, boolean)} with a boolean. 33 * <pre> 34 * public void testAdd() { 35 * double result= fValue1 + fValue2; 36 * assertTrue(result == 5.0); 37 * } 38 * </pre> 39 * 40 * Once the methods are defined you can run them. The framework supports 41 * both a static type safe and more dynamic way to run a test. 42 * In the static way you override the runTest method and define the method to 43 * be invoked. A convenient way to do so is with an anonymous inner class. 44 * <pre> 45 * TestCase test= new MathTest("add") { 46 * public void runTest() { 47 * testAdd(); 48 * } 49 * }; 50 * test.run(); 51 * </pre> 52 * 53 * The dynamic way uses reflection to implement {@link #runTest()}. It dynamically finds 54 * and invokes a method. 55 * In this case the name of the test case has to correspond to the test method 56 * to be run. 57 * <pre> 58 * TestCase test= new MathTest("testAdd"); 59 * test.run(); 60 * </pre> 61 * 62 * The tests to be run can be collected into a TestSuite. JUnit provides 63 * different <i>test runners</i> which can run a test suite and collect the results. 64 * A test runner either expects a static method <code>suite</code> as the entry 65 * point to get a test to run or it will extract the suite automatically. 66 * <pre> 67 * public static Test suite() { 68 * suite.addTest(new MathTest("testAdd")); 69 * suite.addTest(new MathTest("testDivideByZero")); 70 * return suite; 71 * } 72 * </pre> 73 * @see TestResult 74 * @see TestSuite 75 */ 76 public abstract class TestCase extends Assert implements Test { 77 /** 78 * the name of the test case 79 */ 80 private String fName; 81 82 /** 83 * No-arg constructor to enable serialization. This method 84 * is not intended to be used by mere mortals without calling setName(). 85 */ TestCase()86 public TestCase() { 87 fName= null; 88 } 89 /** 90 * Constructs a test case with the given name. 91 */ TestCase(String name)92 public TestCase(String name) { 93 fName= name; 94 } 95 /** 96 * Counts the number of test cases executed by run(TestResult result). 97 */ countTestCases()98 public int countTestCases() { 99 return 1; 100 } 101 /** 102 * Creates a default TestResult object 103 * 104 * @see TestResult 105 */ createResult()106 protected TestResult createResult() { 107 return new TestResult(); 108 } 109 /** 110 * A convenience method to run this test, collecting the results with a 111 * default TestResult object. 112 * 113 * @see TestResult 114 */ run()115 public TestResult run() { 116 TestResult result= createResult(); 117 run(result); 118 return result; 119 } 120 /** 121 * Runs the test case and collects the results in TestResult. 122 */ run(TestResult result)123 public void run(TestResult result) { 124 result.run(this); 125 } 126 /** 127 * Runs the bare test sequence. 128 * @throws Throwable if any exception is thrown 129 */ runBare()130 public void runBare() throws Throwable { 131 Throwable exception= null; 132 setUp(); 133 try { 134 runTest(); 135 } catch (Throwable running) { 136 exception= running; 137 } 138 finally { 139 try { 140 tearDown(); 141 } catch (Throwable tearingDown) { 142 if (exception == null) exception= tearingDown; 143 } 144 } 145 if (exception != null) throw exception; 146 } 147 /** 148 * Override to run the test and assert its state. 149 * @throws Throwable if any exception is thrown 150 */ runTest()151 protected void runTest() throws Throwable { 152 assertNotNull("TestCase.fName cannot be null", fName); // Some VMs crash when calling getMethod(null,null); 153 Method runMethod= null; 154 try { 155 // use getMethod to get all public inherited 156 // methods. getDeclaredMethods returns all 157 // methods of this class but excludes the 158 // inherited ones. 159 runMethod= getClass().getMethod(fName, (Class[])null); 160 } catch (NoSuchMethodException e) { 161 fail("Method \""+fName+"\" not found"); 162 } 163 if (!Modifier.isPublic(runMethod.getModifiers())) { 164 fail("Method \""+fName+"\" should be public"); 165 } 166 167 try { 168 runMethod.invoke(this); 169 } 170 catch (InvocationTargetException e) { 171 e.fillInStackTrace(); 172 throw e.getTargetException(); 173 } 174 catch (IllegalAccessException e) { 175 e.fillInStackTrace(); 176 throw e; 177 } 178 } 179 /** 180 * Sets up the fixture, for example, open a network connection. 181 * This method is called before a test is executed. 182 */ setUp()183 protected void setUp() throws Exception { 184 } 185 /** 186 * Tears down the fixture, for example, close a network connection. 187 * This method is called after a test is executed. 188 */ tearDown()189 protected void tearDown() throws Exception { 190 } 191 /** 192 * Returns a string representation of the test case 193 */ 194 @Override toString()195 public String toString() { 196 return getName() + "(" + getClass().getName() + ")"; 197 } 198 /** 199 * Gets the name of a TestCase 200 * @return the name of the TestCase 201 */ getName()202 public String getName() { 203 return fName; 204 } 205 /** 206 * Sets the name of a TestCase 207 * @param name the name to set 208 */ setName(String name)209 public void setName(String name) { 210 fName= name; 211 } 212 } 213