Single-Value Annotations


The @Ignore annotation is a marker annotationit marks whether a method should be ignored or not. You merely need to test for the presence of the annotation using isAnnotationPresent. Now you need developers to supply a reason for ignoring a test. You will modify the @Ignore annotation to take a reason String as a parameter.


To support a single parameter in an annotation type, you supply a member method named value with an appropriate return type and no parameters. Annotation type member methods cannot take any parameters.

 package sis.testing; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Ignore {    String value(); } 

Mark one of the methods in IgnoreMethodTest with just @Ignore. Do not supply any parameters:

 class IgnoreMethodTest {    @TestMethod public void testA() {}    @TestMethod public void testB() {}    @Ignore()       @TestMethod public void testC() {} } 

Note that @Ignore is a shortcut for @Ignore().

When you compile, you will see an error message:

 annotation testing.Ignore is missing value    @Ignore     ^ 

The compiler uses the corresponding annotation type declaration to ensure that you supplied the proper number of parameters.

Change the test target class, IgnoreMethodTest, to supply a reason with the @Ignore annotation.

 public class TestRunnerTest {    public static final String IGNORE_REASON1 = "because";    // ... } class IgnoreMethodTest {    @TestMethod public void testA() {}    @TestMethod public void testB() {}    @Ignore(TestRunnerTest.IGNORE_REASON1)       @TestMethod public void testC() {} } 

Rerun your tests. They pass, so you haven't broken anything. But you also want the ability to print a list of the ignored methods. Modify the test accordingly:

 @TestMethod public void ignoreMethodTest() {    runTests(IgnoreMethodTest.class);    verifyTests(methodNameA, methodNameB);    assertIgnoreReasons(); } private void assertIgnoreReasons() {    Map<Method, Ignore> ignoredMethods = runner.getIgnoredMethods();    Map.Entry<Method, Ignore> entry = getSoleEntry(ignoredMethods);    assert "testC".equals(entry.getKey().getName()):       "unexpected ignore method: " + entry.getKey();    Ignore ignore = entry.getValue();    assert IGNORE_REASON1.equals(ignore.value()); } private <K, V> Map.Entry<K, V> getSoleEntry(Map<K, V> map) {    assert 1 == map.size(): "expected one entry";    Iterator<Map.Entry<K, V>> it = map.entrySet().iterator();    return it.next(); } 

You return the ignored methods as a collection of mappings between Method objects and the "ignored reason" string. Since you expect there to be only one ignored method, you can introduce the utility method getSoleEntry to extract the single Method key from the Map. In my excitement over figuring out how to use generics (see Lesson 14), I've gone a little overboard here and made getSoleEntry into a generic method that you could use for any collection. There's no reason you couldn't code it specifically to the key and value types of the map.

Now make the necessary changes to TestRunner to get it to store the ignored methods for later extraction:

 package sis.testing; import java.util.*; import java.lang.reflect.*; class TestRunner {    // ...    private Map<Method, Ignore> ignoredMethods = null;    // ...    private void loadTestMethods() {       testMethods = new HashSet<Method>();       ignoredMethods = new HashMap<Method, Ignore>();       for (Method method: testClass.getDeclaredMethods()) {          if (method.isAnnotationPresent(TestMethod.class))             if (method.isAnnotationPresent(Ignore.class)) {                Ignore ignore = method.getAnnotation(Ignore.class);                ignoredMethods.put(method, ignore);             }             else                testMethods.add(method);       }    }    public Map<Method, Ignore> getIgnoredMethods() {       return ignoredMethods;    }    // ... } 

You can send the getAnnotation method to any element that can be annotated, passing it the annotation type name (Ignore.class here). The getAnnotation method returns an annotation type reference to the actual annotation object. Once you have the annotation object reference (ignore), you can send messages to it that are defined in the annotation type interface.

You can now modify the text user interface to display the ignored methods.



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