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. |