diff --git a/doc/ReleaseNotes4.12.md b/doc/ReleaseNotes4.12.md index 7320bf87e5b3..0fe825d13f6c 100644 --- a/doc/ReleaseNotes4.12.md +++ b/doc/ReleaseNotes4.12.md @@ -586,11 +586,6 @@ Follow this link for _IntelliJ IDEA_: [http://www.jetbrains.com/idea/webhelp/act # Miscellaneous -### [Pull request #862:] (https://github.com/junit-team/junit/pull/862) Delete classes that are deprecated for six years - -`JUnit4ClassRunner` was deprecated in JUnit 4.3 (six years and nine major releases ago) with a comment saying "This may disappear as soon as 1 April 2009". We started having some problems with running the tests in JDK 7, and we decided to delete the class and its support classes. Although we try very hard to maintain backwards compatibility, `JUnit4ClassRunner` didn't support `Rule`s, it wasn't designed to be extensible, and it was in an internal package. Please use `BlockJUnit4ClassRunner` instead. - - ### [Pull request #776:](https://github.com/junit-team/junit/pull/776) Add support for [Travis CI](http://travis-ci.org) Travis CI is a free CI server for public Github repositories. Every pull request is run by Travis CI and Github's web interface shows the CI result for each pull request. Every user can use Travis CI for testing her branches, too. diff --git a/src/main/java/org/junit/internal/runners/ClassRoadie.java b/src/main/java/org/junit/internal/runners/ClassRoadie.java new file mode 100644 index 000000000000..df1b45349ca6 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/ClassRoadie.java @@ -0,0 +1,81 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class ClassRoadie { + private RunNotifier notifier; + private TestClass testClass; + private Description description; + private final Runnable runnable; + + public ClassRoadie(RunNotifier notifier, TestClass testClass, + Description description, Runnable runnable) { + this.notifier = notifier; + this.testClass = testClass; + this.description = description; + this.runnable = runnable; + } + + protected void runUnprotected() { + runnable.run(); + } + + protected void addFailure(Throwable targetException) { + notifier.fireTestFailure(new Failure(description, targetException)); + } + + public void runProtected() { + try { + runBefores(); + runUnprotected(); + } catch (FailedBefore e) { + } finally { + runAfters(); + } + } + + private void runBefores() throws FailedBefore { + try { + try { + List befores = testClass.getBefores(); + for (Method before : befores) { + before.invoke(null); + } + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } catch (AssumptionViolatedException e) { + throw new FailedBefore(); + } catch (Throwable e) { + addFailure(e); + throw new FailedBefore(); + } + } + + private void runAfters() { + List afters = testClass.getAfters(); + for (Method after : afters) { + try { + after.invoke(null); + } catch (InvocationTargetException e) { + addFailure(e.getTargetException()); + } catch (Throwable e) { + addFailure(e); // Untested, but seems impossible + } + } + } +} diff --git a/src/main/java/org/junit/internal/runners/FailedBefore.java b/src/main/java/org/junit/internal/runners/FailedBefore.java new file mode 100644 index 000000000000..1036cb69bf0a --- /dev/null +++ b/src/main/java/org/junit/internal/runners/FailedBefore.java @@ -0,0 +1,13 @@ +package org.junit.internal.runners; + +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +class FailedBefore extends Exception { + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java b/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java new file mode 100644 index 000000000000..69a23c448ccd --- /dev/null +++ b/src/main/java/org/junit/internal/runners/JUnit4ClassRunner.java @@ -0,0 +1,147 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; + +import org.junit.runner.Description; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.Filterable; +import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runner.manipulation.Sortable; +import org.junit.runner.manipulation.Sorter; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class JUnit4ClassRunner extends Runner implements Filterable, Sortable { + private final List testMethods; + private TestClass testClass; + + public JUnit4ClassRunner(Class klass) throws InitializationError { + testClass = new TestClass(klass); + testMethods = getTestMethods(); + validate(); + } + + protected List getTestMethods() { + return testClass.getTestMethods(); + } + + protected void validate() throws InitializationError { + MethodValidator methodValidator = new MethodValidator(testClass); + methodValidator.validateMethodsForDefaultRunner(); + methodValidator.assertValid(); + } + + @Override + public void run(final RunNotifier notifier) { + new ClassRoadie(notifier, testClass, getDescription(), new Runnable() { + public void run() { + runMethods(notifier); + } + }).runProtected(); + } + + protected void runMethods(final RunNotifier notifier) { + for (Method method : testMethods) { + invokeTestMethod(method, notifier); + } + } + + @Override + public Description getDescription() { + Description spec = Description.createSuiteDescription(getName(), classAnnotations()); + List testMethods = this.testMethods; + for (Method method : testMethods) { + spec.addChild(methodDescription(method)); + } + return spec; + } + + protected Annotation[] classAnnotations() { + return testClass.getJavaClass().getAnnotations(); + } + + protected String getName() { + return getTestClass().getName(); + } + + protected Object createTest() throws Exception { + return getTestClass().getConstructor().newInstance(); + } + + protected void invokeTestMethod(Method method, RunNotifier notifier) { + Description description = methodDescription(method); + Object test; + try { + test = createTest(); + } catch (InvocationTargetException e) { + testAborted(notifier, description, e.getCause()); + return; + } catch (Exception e) { + testAborted(notifier, description, e); + return; + } + TestMethod testMethod = wrapMethod(method); + new MethodRoadie(test, testMethod, notifier, description).run(); + } + + private void testAborted(RunNotifier notifier, Description description, + Throwable e) { + notifier.fireTestStarted(description); + notifier.fireTestFailure(new Failure(description, e)); + notifier.fireTestFinished(description); + } + + protected TestMethod wrapMethod(Method method) { + return new TestMethod(method, testClass); + } + + protected String testName(Method method) { + return method.getName(); + } + + protected Description methodDescription(Method method) { + return Description.createTestDescription(getTestClass().getJavaClass(), testName(method), testAnnotations(method)); + } + + protected Annotation[] testAnnotations(Method method) { + return method.getAnnotations(); + } + + public void filter(Filter filter) throws NoTestsRemainException { + for (Iterator iter = testMethods.iterator(); iter.hasNext(); ) { + Method method = iter.next(); + if (!filter.shouldRun(methodDescription(method))) { + iter.remove(); + } + } + if (testMethods.isEmpty()) { + throw new NoTestsRemainException(); + } + } + + public void sort(final Sorter sorter) { + Collections.sort(testMethods, new Comparator() { + public int compare(Method o1, Method o2) { + return sorter.compare(methodDescription(o1), methodDescription(o2)); + } + }); + } + + protected TestClass getTestClass() { + return testClass; + } +} \ No newline at end of file diff --git a/src/main/java/org/junit/internal/runners/MethodRoadie.java b/src/main/java/org/junit/internal/runners/MethodRoadie.java new file mode 100644 index 000000000000..01a476bd7341 --- /dev/null +++ b/src/main/java/org/junit/internal/runners/MethodRoadie.java @@ -0,0 +1,163 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.junit.internal.AssumptionViolatedException; +import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.TestTimedOutException; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class MethodRoadie { + private final Object test; + private final RunNotifier notifier; + private final Description description; + private TestMethod testMethod; + + public MethodRoadie(Object test, TestMethod method, RunNotifier notifier, Description description) { + this.test = test; + this.notifier = notifier; + this.description = description; + testMethod = method; + } + + public void run() { + if (testMethod.isIgnored()) { + notifier.fireTestIgnored(description); + return; + } + notifier.fireTestStarted(description); + try { + long timeout = testMethod.getTimeout(); + if (timeout > 0) { + runWithTimeout(timeout); + } else { + runTest(); + } + } finally { + notifier.fireTestFinished(description); + } + } + + private void runWithTimeout(final long timeout) { + runBeforesThenTestThenAfters(new Runnable() { + + public void run() { + ExecutorService service = Executors.newSingleThreadExecutor(); + Callable callable = new Callable() { + public Object call() throws Exception { + runTestMethod(); + return null; + } + }; + Future result = service.submit(callable); + service.shutdown(); + try { + boolean terminated = service.awaitTermination(timeout, + TimeUnit.MILLISECONDS); + if (!terminated) { + service.shutdownNow(); + } + result.get(0, TimeUnit.MILLISECONDS); // throws the exception if one occurred during the invocation + } catch (TimeoutException e) { + addFailure(new TestTimedOutException(timeout, TimeUnit.MILLISECONDS)); + } catch (Exception e) { + addFailure(e); + } + } + }); + } + + public void runTest() { + runBeforesThenTestThenAfters(new Runnable() { + public void run() { + runTestMethod(); + } + }); + } + + public void runBeforesThenTestThenAfters(Runnable test) { + try { + runBefores(); + test.run(); + } catch (FailedBefore e) { + } catch (Exception e) { + throw new RuntimeException("test should never throw an exception to this level"); + } finally { + runAfters(); + } + } + + protected void runTestMethod() { + try { + testMethod.invoke(test); + if (testMethod.expectsException()) { + addFailure(new AssertionError("Expected exception: " + testMethod.getExpectedException().getName())); + } + } catch (InvocationTargetException e) { + Throwable actual = e.getTargetException(); + if (actual instanceof AssumptionViolatedException) { + return; + } else if (!testMethod.expectsException()) { + addFailure(actual); + } else if (testMethod.isUnexpected(actual)) { + String message = "Unexpected exception, expected<" + testMethod.getExpectedException().getName() + "> but was<" + + actual.getClass().getName() + ">"; + addFailure(new Exception(message, actual)); + } + } catch (Throwable e) { + addFailure(e); + } + } + + private void runBefores() throws FailedBefore { + try { + try { + List befores = testMethod.getBefores(); + for (Method before : befores) { + before.invoke(test); + } + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } catch (AssumptionViolatedException e) { + throw new FailedBefore(); + } catch (Throwable e) { + addFailure(e); + throw new FailedBefore(); + } + } + + private void runAfters() { + List afters = testMethod.getAfters(); + for (Method after : afters) { + try { + after.invoke(test); + } catch (InvocationTargetException e) { + addFailure(e.getTargetException()); + } catch (Throwable e) { + addFailure(e); // Untested, but seems impossible + } + } + } + + protected void addFailure(Throwable e) { + notifier.fireTestFailure(new Failure(description, e)); + } +} + diff --git a/src/main/java/org/junit/internal/runners/MethodValidator.java b/src/main/java/org/junit/internal/runners/MethodValidator.java new file mode 100644 index 000000000000..ba9c9d1546ba --- /dev/null +++ b/src/main/java/org/junit/internal/runners/MethodValidator.java @@ -0,0 +1,97 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class MethodValidator { + + private final List errors = new ArrayList(); + + private TestClass testClass; + + public MethodValidator(TestClass testClass) { + this.testClass = testClass; + } + + public void validateInstanceMethods() { + validateTestMethods(After.class, false); + validateTestMethods(Before.class, false); + validateTestMethods(Test.class, false); + + List methods = testClass.getAnnotatedMethods(Test.class); + if (methods.size() == 0) { + errors.add(new Exception("No runnable methods")); + } + } + + public void validateStaticMethods() { + validateTestMethods(BeforeClass.class, true); + validateTestMethods(AfterClass.class, true); + } + + public List validateMethodsForDefaultRunner() { + validateNoArgConstructor(); + validateStaticMethods(); + validateInstanceMethods(); + return errors; + } + + public void assertValid() throws InitializationError { + if (!errors.isEmpty()) { + throw new InitializationError(errors); + } + } + + public void validateNoArgConstructor() { + try { + testClass.getConstructor(); + } catch (Exception e) { + errors.add(new Exception("Test class should have public zero-argument constructor", e)); + } + } + + private void validateTestMethods(Class annotation, + boolean isStatic) { + List methods = testClass.getAnnotatedMethods(annotation); + + for (Method each : methods) { + if (Modifier.isStatic(each.getModifiers()) != isStatic) { + String state = isStatic ? "should" : "should not"; + errors.add(new Exception("Method " + each.getName() + "() " + + state + " be static")); + } + if (!Modifier.isPublic(each.getDeclaringClass().getModifiers())) { + errors.add(new Exception("Class " + each.getDeclaringClass().getName() + + " should be public")); + } + if (!Modifier.isPublic(each.getModifiers())) { + errors.add(new Exception("Method " + each.getName() + + " should be public")); + } + if (each.getReturnType() != Void.TYPE) { + errors.add(new Exception("Method " + each.getName() + + " should be void")); + } + if (each.getParameterTypes().length != 0) { + errors.add(new Exception("Method " + each.getName() + + " should have no parameters")); + } + } + } +} diff --git a/src/main/java/org/junit/internal/runners/TestClass.java b/src/main/java/org/junit/internal/runners/TestClass.java new file mode 100644 index 000000000000..1abaeeab688a --- /dev/null +++ b/src/main/java/org/junit/internal/runners/TestClass.java @@ -0,0 +1,109 @@ +package org.junit.internal.runners; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.internal.MethodSorter; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class TestClass { + private final Class klass; + + public TestClass(Class klass) { + this.klass = klass; + } + + public List getTestMethods() { + return getAnnotatedMethods(Test.class); + } + + List getBefores() { + return getAnnotatedMethods(BeforeClass.class); + } + + List getAfters() { + return getAnnotatedMethods(AfterClass.class); + } + + public List getAnnotatedMethods(Class annotationClass) { + List results = new ArrayList(); + for (Class eachClass : getSuperClasses(klass)) { + Method[] methods = MethodSorter.getDeclaredMethods(eachClass); + for (Method eachMethod : methods) { + Annotation annotation = eachMethod.getAnnotation(annotationClass); + if (annotation != null && !isShadowed(eachMethod, results)) { + results.add(eachMethod); + } + } + } + if (runsTopToBottom(annotationClass)) { + Collections.reverse(results); + } + return results; + } + + private boolean runsTopToBottom(Class annotation) { + return annotation.equals(Before.class) || annotation.equals(BeforeClass.class); + } + + private boolean isShadowed(Method method, List results) { + for (Method each : results) { + if (isShadowed(method, each)) { + return true; + } + } + return false; + } + + private boolean isShadowed(Method current, Method previous) { + if (!previous.getName().equals(current.getName())) { + return false; + } + if (previous.getParameterTypes().length != current.getParameterTypes().length) { + return false; + } + for (int i = 0; i < previous.getParameterTypes().length; i++) { + if (!previous.getParameterTypes()[i].equals(current.getParameterTypes()[i])) { + return false; + } + } + return true; + } + + private List> getSuperClasses(Class testClass) { + ArrayList> results = new ArrayList>(); + Class current = testClass; + while (current != null) { + results.add(current); + current = current.getSuperclass(); + } + return results; + } + + public Constructor getConstructor() throws SecurityException, NoSuchMethodException { + return klass.getConstructor(); + } + + public Class getJavaClass() { + return klass; + } + + public String getName() { + return klass.getName(); + } + +} diff --git a/src/main/java/org/junit/internal/runners/TestMethod.java b/src/main/java/org/junit/internal/runners/TestMethod.java new file mode 100644 index 000000000000..821e193d53af --- /dev/null +++ b/src/main/java/org/junit/internal/runners/TestMethod.java @@ -0,0 +1,71 @@ +package org.junit.internal.runners; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.Test.None; +import org.junit.runners.BlockJUnit4ClassRunner; + +/** + * @deprecated Included for backwards compatibility with JUnit 4.4. Will be + * removed in the next major release. Please use + * {@link BlockJUnit4ClassRunner} in place of {@link JUnit4ClassRunner}. + */ +@Deprecated +public class TestMethod { + private final Method method; + private TestClass testClass; + + public TestMethod(Method method, TestClass testClass) { + this.method = method; + this.testClass = testClass; + } + + public boolean isIgnored() { + return method.getAnnotation(Ignore.class) != null; + } + + public long getTimeout() { + Test annotation = method.getAnnotation(Test.class); + if (annotation == null) { + return 0; + } + long timeout = annotation.timeout(); + return timeout; + } + + protected Class getExpectedException() { + Test annotation = method.getAnnotation(Test.class); + if (annotation == null || annotation.expected() == None.class) { + return null; + } else { + return annotation.expected(); + } + } + + boolean isUnexpected(Throwable exception) { + return !getExpectedException().isAssignableFrom(exception.getClass()); + } + + boolean expectsException() { + return getExpectedException() != null; + } + + List getBefores() { + return testClass.getAnnotatedMethods(Before.class); + } + + List getAfters() { + return testClass.getAnnotatedMethods(After.class); + } + + public void invoke(Object test) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + method.invoke(test); + } + +} diff --git a/src/test/java/org/junit/tests/AllTests.java b/src/test/java/org/junit/tests/AllTests.java index 47c25418f8d1..00c259b77320 100644 --- a/src/test/java/org/junit/tests/AllTests.java +++ b/src/test/java/org/junit/tests/AllTests.java @@ -27,6 +27,7 @@ import org.junit.tests.assertion.AssertionTest; import org.junit.tests.assertion.ComparisonFailureTest; import org.junit.tests.assertion.MultipleFailureExceptionTest; +import org.junit.tests.deprecated.JUnit4ClassRunnerTest; import org.junit.tests.description.AnnotatedDescriptionTest; import org.junit.tests.description.SuiteDescriptionTest; import org.junit.tests.description.TestDescriptionMethodNameTest; @@ -100,6 +101,7 @@ import org.junit.tests.running.methods.ParameterizedTestMethodTest; import org.junit.tests.running.methods.TestMethodTest; import org.junit.tests.running.methods.TimeoutTest; +import org.junit.tests.validation.BadlyFormedClassesTest; import org.junit.tests.validation.FailedConstructionTest; import org.junit.tests.validation.ValidationTest; import org.junit.validator.PublicClassValidatorTest; @@ -107,6 +109,7 @@ // These test files need to be cleaned. See // https://sourceforge.net/pm/task.php?func=detailtask&project_task_id=136507&group_id=15278&group_project_id=51407 +@SuppressWarnings("deprecation") @RunWith(Suite.class) @SuiteClasses({ AssumptionTest.class, @@ -145,6 +148,7 @@ SystemExitTest.class, JUnitCoreReturnsCorrectExitCodeTest.class, SuiteMethodTest.class, + BadlyFormedClassesTest.class, IgnoreClassTest.class, OldTestClassAdaptingListenerTest.class, AnnotatedDescriptionTest.class, @@ -161,6 +165,7 @@ MatcherTest.class, ObjectContractTest.class, TheoriesPerformanceTest.class, + JUnit4ClassRunnerTest.class, UseSuiteAsASuperclassTest.class, FilterableTest.class, FilterTest.class, diff --git a/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java b/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java new file mode 100644 index 000000000000..43983ba97637 --- /dev/null +++ b/src/test/java/org/junit/tests/deprecated/JUnit4ClassRunnerTest.java @@ -0,0 +1,64 @@ +package org.junit.tests.deprecated; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import org.junit.Test; +import org.junit.internal.runners.JUnit4ClassRunner; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.RunWith; + +/** + * @deprecated This is a simple smoke test to make sure the old JUnit4ClassRunner basically works. + * Delete this test when JUnit4ClassRunner goes to the Great Heap In The Sky. + */ +@Deprecated +public class JUnit4ClassRunnerTest { + + @SuppressWarnings("deprecation") + @RunWith(JUnit4ClassRunner.class) + public static class Example { + @Test + public void success() { + } + + @Test + public void failure() { + fail(); + } + } + + @Test + public void runWithOldJUnit4ClassRunner() { + Result result = JUnitCore.runClasses(Example.class); + assertThat(result.getRunCount(), is(2)); + assertThat(result.getFailureCount(), is(1)); + } + + @SuppressWarnings("deprecation") + @RunWith(JUnit4ClassRunner.class) + public static class UnconstructableExample { + public UnconstructableExample() { + throw new UnsupportedOperationException(); + } + + @Test + public void success() { + } + + @Test + public void failure() { + fail(); + } + } + + + @Test + public void runWithOldJUnit4ClassRunnerAndBadConstructor() { + Result result = JUnitCore.runClasses(UnconstructableExample.class); + assertThat(result.getRunCount(), is(2)); + assertThat(result.getFailureCount(), is(2)); + } +} diff --git a/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java b/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java new file mode 100644 index 000000000000..44cf26479f4c --- /dev/null +++ b/src/test/java/org/junit/tests/validation/BadlyFormedClassesTest.java @@ -0,0 +1,73 @@ +package org.junit.tests.validation; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; +import org.junit.internal.runners.JUnit4ClassRunner; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; +import org.junit.runner.RunWith; +import org.junit.runner.notification.Failure; + +@SuppressWarnings("deprecation") +public class BadlyFormedClassesTest { + public static class FaultyConstructor { + public FaultyConstructor() throws Exception { + throw new Exception("Thrown during construction"); + } + + @Test + public void someTest() { + /* + * Empty test just to fool JUnit and IDEs into running this class as + * a JUnit test + */ + } + } + + ; + + @RunWith(JUnit4ClassRunner.class) + public static class BadBeforeMethodWithLegacyRunner { + @Before + void before() { + + } + + @Test + public void someTest() { + } + } + + ; + + public static class NoTests { + // class without tests + } + + @Test + public void constructorException() { + String message = exceptionMessageFrom(FaultyConstructor.class); + assertEquals("Thrown during construction", message); + } + + @Test + public void noRunnableMethods() { + assertEquals("No runnable methods", exceptionMessageFrom(NoTests.class)); + } + + @Test + public void badBeforeMethodWithLegacyRunner() { + assertEquals("Method before should be public", + exceptionMessageFrom(BadBeforeMethodWithLegacyRunner.class)); + } + + private String exceptionMessageFrom(Class testClass) { + JUnitCore core = new JUnitCore(); + Result result = core.run(testClass); + Failure failure = result.getFailures().get(0); + String message = failure.getException().getMessage(); + return message; + } +}