The TestMethod Annotation


The @TestMethod Annotation

In order to be able to refactor tests, you must be able to mark the test methods so that other newly extracted methods are not considered tests. The @TestMethod annotation precedes the method signature for each method you want to designate as a test. Annotate the two test methods (singleMethodTest and multipleMethodTest) in TestRunnerTest with @TestMethod. Also annotate the three additional test methods in the miniclasses (SingleMethodTest and MultipleMethodTest) used by the TestRunnerTest tests.

 package sis.testing; import java.util.*; import java.lang.reflect.*; public class TestRunnerTest {    private TestRunner runner;    private static final String methodNameA = "testA";    private static final String methodNameB = "testB";    @TestMethod    public void singleMethodTest() {       runTests(SingleMethodTest.class);       verifyTests(methodNameA);    }    @TestMethod    public void multipleMethodTest() {       runTests(MultipleMethodTest.class);       verifyTests(methodNameA, methodNameB);    }    private void runTests(Class testClass) {       runner = new TestRunner(testClass);       runner.run();    }    private void verifyTests(String... expectedTestMethodNames) {       verifyNumberOfTests(expectedTestMethodNames);       verifyMethodNames(expectedTestMethodNames);       verifyCounts(expectedTestMethodNames);    }    private void verifyCounts(String... testMethodNames) {       assert testMethodNames.length == runner.passed() :          "expected " + testMethodNames.length + " passed";       assert 0 == runner.failed() : "expected no failures";    }    private void verifyNumberOfTests(String... testMethodNames) {       assert testMethodNames.length == runner.getTestMethods().size() :          "expected " + testMethodNames.length + " test method(s)";    }    private void verifyMethodNames(String... testMethodNames) {       Set<String> actualMethodNames = getTestMethodNames();       for (String methodName: testMethodNames)          assert actualMethodNames.contains(methodName):             "expected " + methodName + " as test method";    }    private Set<String> getTestMethodNames() {       Set<String> methodNames = new HashSet<String>();       for (Method method: runner.getTestMethods())          methodNames.add(method.getName());       return methodNames;    } } class SingleMethodTest {    @TestMethod public void testA() {} } class MultipleMethodTest {    @TestMethod public void testA() {}    @TestMethod public void testB() {} } 

The @TestMethod annotation may appear after any method modifiers such as public or static. The annotation must appear before the signature of the method (which starts with the return type of the method).

To declare the @TestMethod annotation type, you create what looks a lot like an interface declaration:

 package sis.testing; public @interface TestMethod {} 

The only difference between an interface declaration and an annotation type declaration is that you put an "at" sign (@) before the keyword interface in an interface declaration. There can be space between @ and interface, but the convention is to abut the two.

The code will now compile and you can execute your tests, but you will see at least one IllegalAccessException stack trace. The code in TestRunner still treats every method as a test method, including the private methods you just extracted. The reflection code in TestRunner is unable to invoke these private methods. It's time to introduce code in TestRunner to look for the @TestMethod annotations:

 private void loadTestMethods() {    testMethods = new HashSet<Method>();    for (Method method: testClass.getDeclaredMethods())       if (method.isAnnotationPresent(TestMethod.class))          testMethods.add(method); } 

One line of code is all it takes. You send the message isAnnotationPresent to the Method object, passing in the type (TestMethod.class) of the annotation. If isAnnotationPresent returns true, you add the Method object to the list of tests.

Now the test executes but returns improper results:

 runAllTests:      [java] passed: 0 failed: 0 

You're expecting to see two passed tests but no tests are registeredthe isAnnotationPresent method is always returning false.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net