Skip to content

Commit

Permalink
Any class can be a category. Added Category exclusion.
Browse files Browse the repository at this point in the history
  • Loading branch information
David Saff committed Nov 24, 2009
1 parent ce280f0 commit cec8e3e
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 68 deletions.
8 changes: 5 additions & 3 deletions doc/ReleaseNotes4.8.txt
Expand Up @@ -5,12 +5,14 @@
From a given set of test classes, the `Categories` runner
runs only the classes and methods
that are annotated with either the category given with the `@IncludeCategory`
annotation, or a subtype of that category.
annotation, or a subtype of that category. Either classes or interfaces can be
used as categories. Subtyping works, so if you say @IncludeCategory(SuperClass.class),
a test marked @Category({SubClass.class}) will be run.

Example:

public interface FastTests extends CategoryType {}
public interface SlowTests extends CategoryType {}
public interface FastTests { /* category marker */ }
public interface SlowTests { /* category marker */ }

public static class A {
@Test
Expand Down
116 changes: 70 additions & 46 deletions src/main/java/org/junit/experimental/categories/Categories.java
Expand Up @@ -14,62 +14,76 @@
import org.junit.runners.model.RunnerBuilder;

/**
* From a given set of test classes, runs only the classes and methods
* that are annotated with either the category given with the @IncludeCategory
* From a given set of test classes, runs only the classes and methods that are
* annotated with either the category given with the @IncludeCategory
* annotation, or a subtype of that category.
*
* Example:
<pre>
public interface FastTests extends CategoryType {}
public interface SlowTests extends CategoryType {}
public static class A {
@Test
public void a() {
fail();
}
@Category(SlowTests.class)
@Test
public void b() {
}
}
@Category({SlowTests.class, FastTests.class})
public static class B {
@Test
public void c() {
}
}
@RunWith(Categories.class)
@IncludeCategory(SlowTests.class)
@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
public static class SlowTestSuite {}
</pre>
*
* <pre>
* public interface FastTests extends CategoryType {
* }
*
* public interface SlowTests extends CategoryType {
* }
*
* public static class A {
* &#064;Test
* public void a() {
* fail();
* }
*
* &#064;Category(SlowTests.class)
* &#064;Test
* public void b() {
* }
* }
*
* &#064;Category( { SlowTests.class, FastTests.class })
* public static class B {
* &#064;Test
* public void c() {
*
* }
* }
*
* &#064;RunWith(Categories.class)
* &#064;IncludeCategory(SlowTests.class)
* &#064;SuiteClasses( { A.class, B.class })
* // Note that Categories is a kind of Suite
* public static class SlowTestSuite {
* }
* </pre>
*/
public class Categories extends Suite {
@Retention(RetentionPolicy.RUNTIME)
public @interface IncludeCategory {
public Class<? extends CategoryType> value();
public Class<?> value();
}

@Retention(RetentionPolicy.RUNTIME)
public @interface ExcludeCategory {
public Class<?> value();
}

public static class CategoryFilter extends Filter {
public static CategoryFilter include(
Class<? extends CategoryType> categoryClass) {
return new CategoryFilter(categoryClass);
public static CategoryFilter include(Class<?> categoryType) {
return new CategoryFilter(categoryType, null);
}

private final Class<? extends CategoryType> fCategoryClass;
private final Class<?> fIncluded;

public CategoryFilter(Class<? extends CategoryType> categoryClass) {
fCategoryClass= categoryClass;
private final Class<?> fExcluded;

public CategoryFilter(Class<?> includedCategory,
Class<?> excludedCategory) {
fIncluded= includedCategory;
fExcluded= excludedCategory;
}

@Override
public String describe() {
return "category " + fCategoryClass;
return "category " + fIncluded;
}

@Override
Expand All @@ -88,10 +102,13 @@ public boolean shouldRun(Description description) {
private boolean hasCorrectCategoryAnnotation(Description description) {
Category annotation= description.getAnnotation(Category.class);
if (annotation == null)
return false;
for (Class<? extends CategoryType> each : annotation.value())
if (fCategoryClass.isAssignableFrom(each))
return fIncluded == null;
for (Class<?> each : annotation.value()) {
if (fExcluded != null && fExcluded.isAssignableFrom(each))
return false;
if (fIncluded == null || fIncluded.isAssignableFrom(each))
return true;
}
return false;
}
}
Expand All @@ -100,13 +117,20 @@ public Categories(Class<?> klass, RunnerBuilder builder)
throws InitializationError {
super(klass, builder);
try {
filter(new CategoryFilter(getCategory(klass)));
filter(new CategoryFilter(getIncludedCategory(klass),
getExcludedCategory(klass)));
} catch (NoTestsRemainException e) {
throw new InitializationError(e);
}
}

private Class<? extends CategoryType> getCategory(Class<?> klass) {
return klass.getAnnotation(IncludeCategory.class).value();
private Class<?> getIncludedCategory(Class<?> klass) {
IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class);
return annotation == null ? null : annotation.value();
}

private Class<?> getExcludedCategory(Class<?> klass) {
ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class);
return annotation == null ? null : annotation.value();
}
}
Expand Up @@ -40,5 +40,5 @@ public void c() {
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Category {
Class<? extends CategoryType>[] value();
Class<?>[] value();
}
11 changes: 0 additions & 11 deletions src/main/java/org/junit/experimental/categories/CategoryType.java

This file was deleted.

Expand Up @@ -7,10 +7,10 @@
import static org.junit.experimental.results.PrintableResult.testResult;
import static org.junit.experimental.results.ResultMatchers.isSuccessful;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.experimental.categories.CategoryType;
import org.junit.experimental.categories.Categories;
import org.junit.experimental.categories.Category;
import org.junit.experimental.categories.Categories.CategoryFilter;
import org.junit.experimental.categories.Categories.ExcludeCategory;
import org.junit.experimental.categories.Categories.IncludeCategory;
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
Expand All @@ -23,12 +23,12 @@
import org.junit.runners.model.InitializationError;

public class CategoryTest {
public interface FastTests extends CategoryType {

public interface FastTests {
// category marker
}

public interface SlowTests extends CategoryType {

public interface SlowTests {
// category marker
}

public static class A {
Expand Down Expand Up @@ -79,6 +79,45 @@ public void testCountOnJustA() {
public void testCount() {
assertThat(testResult(SlowTestSuite.class), isSuccessful());
}

public static class Category1 {}
public static class Category2 {}

public static class SomeAreSlow {
@Test public void noCategory() {}
@Category(Category1.class) @Test public void justCategory1() {}
@Category(Category2.class) @Test public void justCategory2() {}
@Category({Category1.class, Category2.class}) @Test public void both() {}
}

@RunWith(Categories.class)
@ExcludeCategory(Category1.class)
@SuiteClasses( { SomeAreSlow.class })
public static class SomeAreSlowSuite {
}

@Test
public void testCountOnAWithoutSlowTests() {
Result result= JUnitCore.runClasses(SomeAreSlowSuite.class);
assertThat(testResult(SomeAreSlowSuite.class), isSuccessful());
assertEquals(2, result.getRunCount());
assertTrue(result.wasSuccessful());
}

@RunWith(Categories.class)
@ExcludeCategory(Category1.class)
@IncludeCategory(Category2.class)
@SuiteClasses( { SomeAreSlow.class })
public static class IncludeAndExcludeSuite {
}

@Test
public void testsThatAreBothIncludedAndExcludedAreIncluded() {
Result result= JUnitCore.runClasses(IncludeAndExcludeSuite.class);
assertThat(testResult(SomeAreSlowSuite.class), isSuccessful());
assertEquals(1, result.getRunCount());
assertTrue(result.wasSuccessful());
}

@RunWith(Suite.class)
@SuiteClasses( { A.class, B.class, C.class })
Expand Down Expand Up @@ -149,7 +188,7 @@ public void ifNoTestsToRunUseErrorRunner() {

@Test
public void describeACategoryFilter() {
CategoryFilter filter= new CategoryFilter(SlowTests.class);
CategoryFilter filter= CategoryFilter.include(SlowTests.class);
assertEquals("category " + SlowTests.class, filter.describe());
}

Expand Down Expand Up @@ -192,4 +231,22 @@ public static class RunSlowFromVerySlow {
@Test public void subclassesOfIncludedCategoriesAreRun() {
assertThat(testResult(RunSlowFromVerySlow.class), isSuccessful());
}

public static class ClassAsCategory {

}

public static class OneMoreTest {
@Category(ClassAsCategory.class) @Test public void a() {}
}

@RunWith(Categories.class)
@IncludeCategory(ClassAsCategory.class)
@SuiteClasses( { OneMoreTest.class })
public static class RunClassAsCategory {
}

@Test public void classesCanBeCategories() {
assertThat(testResult(RunClassAsCategory.class), isSuccessful());
}
}

0 comments on commit cec8e3e

Please sign in to comment.