/* * Copyright 2006 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jdave.runner; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import jdave.ResultsAdapter; import jdave.SpecVisitorAdapter; import jdave.Specification; import org.junit.Ignore; import org.junit.Test; /** * @author Pekka Enberg * @author Lasse Koskela */ public class SpecRunnerTest { private List<String> methods = new ArrayList<String>(); private SpecRunner runner = new SpecRunner(); @Test public void testShouldNotifyResultsOfAllPublicMethods() throws Exception { assertTrue(methods.isEmpty()); runner.run(BooleanSpec.class, new SpecVisitorAdapter(new ResultsAdapter() { @Override public void expected(Method method) { methods.add(method.getName()); } })); Collections.sort(methods); assertEquals(5, methods.size()); assertEquals("anyBehavior", methods.get(0)); assertEquals("inheritedBehavior", methods.get(1)); assertEquals("shouldBeEqualToTrue", methods.get(2)); assertEquals("shouldEqualToFalse", methods.get(3)); assertEquals("shouldNotBeEqualToTrue", methods.get(4)); } @Test public void testShouldInvokeAllSpecificationMethods() throws Exception { BooleanSpec.actualCalls.clear(); BaseSpec.actualCalls.clear(); runner.run(BooleanSpec.class, new SpecVisitorAdapter(new ResultsAdapter())); Collections.sort(BooleanSpec.actualCalls); assertEquals(Arrays.asList("anyBehavior", "inheritedBehavior"), BaseSpec.actualCalls); assertEquals(Arrays.asList("shouldBeEqualToTrue", "shouldEqualToFalse", "shouldNotBeEqualToTrue"), BooleanSpec.actualCalls); } @Test public void testShouldNotifyCallbackWhenContextIsStarted() throws Exception { SpecVisitorAdapter adapter = new SpecVisitorAdapter(new ResultsAdapter()); runner.run(BooleanSpec.class, adapter); assertEquals(Arrays.asList("CommonContext", "FalseBoolean", "TrueBoolean"), adapter .getContextNames()); } @Test public void testShouldSkipIgnoredContexts() throws Exception { SpecVisitorAdapter adapter = new SpecVisitorAdapter(new ResultsAdapter()); runner.run(SpecWithIgnoredContexts.class, adapter); assertFalse(adapter.getContextNames().contains("ContextWithDefaultVisibility")); assertFalse(adapter.getContextNames().contains("ContextWithJUnit4IgnoreAnnotation")); assertTrue(adapter.getContextNames().contains("TheOnlyProperContext")); } @Test public void testShouldNotifyCallbackWhenContextHasFinished() throws Exception { SpecVisitorAdapter adapter = new SpecVisitorAdapter(new ResultsAdapter()); runner.run(BooleanSpec.class, adapter); assertEquals(Arrays.asList("CommonContext", "FalseBoolean", "TrueBoolean"), adapter .getFinishedContextNames()); } @Test public void testShouldCallDestroyForEachMethod() throws Exception { BooleanSpec.destroyCalled = 0; runner.run(BooleanSpec.class, new SpecVisitorAdapter(new ResultsAdapter())); assertEquals(4, BooleanSpec.destroyCalled); } @Test public void testShouldCallSpecCreateForEachMethod() throws Exception { BooleanSpec.specCreateCalled = 0; runner.run(BooleanSpec.class, new SpecVisitorAdapter(new ResultsAdapter())); assertEquals(5, BooleanSpec.specCreateCalled); } @Test public void testShouldCallSpecDestroyForEachMethod() throws Exception { BooleanSpec.specDestroyCalled = 0; runner.run(BooleanSpec.class, new SpecVisitorAdapter(new ResultsAdapter())); assertEquals(5, BooleanSpec.specDestroyCalled); } @Test public void testShouldCallSpecDestroyEvenIfContextDestroyCrashes() { SpecWithCrashingContextDestroy.specDestroyCalled = 0; runner.run(SpecWithCrashingContextDestroy.class, new SpecVisitorAdapter( new ResultsAdapter())); assertEquals(1, SpecWithCrashingContextDestroy.specDestroyCalled); } @Test public void testShouldCallOnceBeforeExactlyOnce() throws Exception { BooleanSpec.onceBeforeCalled = 0; runner.run(BooleanSpec.class, new SpecVisitorAdapter(new ResultsAdapter())); assertEquals(1, BooleanSpec.onceBeforeCalled); } @Test public void testShouldCallOnceAfterExactlyOnce() throws Exception { BooleanSpec.onceAfterCalled = 0; runner.run(BooleanSpec.class, new SpecVisitorAdapter(new ResultsAdapter())); assertEquals(1, BooleanSpec.onceAfterCalled); } @Test public void testShouldCallOnceAfterEvenIfContextDestroyCrashes() { SpecWithCrashingContextDestroy.onceAfterCalled = 0; runner.run(SpecWithCrashingContextDestroy.class, new SpecVisitorAdapter( new ResultsAdapter())); assertEquals(1, SpecWithCrashingContextDestroy.onceAfterCalled); } @Test public void testReportsErrorIfSpecificationConstructionFails() { final List<Method> errors = new ArrayList<Method>(); runner.run(FailingSpec.class, new SpecVisitorAdapter(new ResultsAdapter() { @Override public void error(Method method, Throwable t) { errors.add(method); } })); assertEquals(1, errors.size()); assertEquals("someBehavior", errors.get(0).getName()); } @Test public void testAllowsContextHavingCreateMethodWithVoidReturnValue() throws Exception { SpecForOtherCreations.whenCreateIsVoid = 0; runner.run(SpecForOtherCreations.class, new SpecVisitorAdapter(new ResultsAdapter())); assertEquals(1, SpecForOtherCreations.whenCreateIsVoid); } @Test public void testAllowsContextWithoutCreateMethod() throws Exception { SpecForOtherCreations.whenCreateDoesNotExist = 0; runner.run(SpecForOtherCreations.class, new SpecVisitorAdapter(new ResultsAdapter())); assertEquals(1, SpecForOtherCreations.whenCreateDoesNotExist); } public static class BaseSpec extends Specification<Boolean> { public static List<String> actualCalls = new ArrayList<String>(); public class CommonContext { public void anyBehavior() { actualCalls.add("anyBehavior"); } } public abstract class BaseContext { public void inheritedBehavior() { actualCalls.add("inheritedBehavior"); } } } public static class BooleanSpec extends BaseSpec { public static List<String> actualCalls = new ArrayList<String>(); public static int destroyCalled; public static int specCreateCalled; public static int specDestroyCalled; public static int onceBeforeCalled; public static int onceAfterCalled; public static void onceBefore() { onceBeforeCalled++; } public static void onceAfter() { onceAfterCalled++; } public class FalseBoolean extends BaseContext { public Boolean create() { return false; } public void shouldEqualToFalse() { actualCalls.add("shouldEqualToFalse"); } public void shouldNotBeEqualToTrue() { actualCalls.add("shouldNotBeEqualToTrue"); } protected void protectedMethod() { actualCalls.add("protectedMethod"); } @SuppressWarnings("unused") private void privateMethod() { actualCalls.add("privateMethod"); } void packageProtectedMethod() { actualCalls.add("packageProtectedMethod"); } public void methodWhichTakesParameters(Object obj) { actualCalls.add("methodWhichTakesParameters"); } public void destroy() { destroyCalled++; } } public class TrueBoolean { public Boolean create() { return true; } public void shouldBeEqualToTrue() { actualCalls.add("shouldBeEqualToTrue"); } public void destroy() { destroyCalled++; } } public class ContextWithoutBehaviors { } public abstract class SomeAbstractClass { } public static class SomeHelperClass { public void thisIsNotBehavior() { } } @SuppressWarnings("unused") private class SomePrivateClass { } class SomePackageProtectedClass { } protected class SomeProtectedClass { } @Override public void create() { specCreateCalled++; } @Override public void destroy() { specDestroyCalled++; } } public static class SpecForOtherCreations extends Specification<Void> { public static int whenCreateIsVoid = 0; public static int whenCreateDoesNotExist = 0; public class ContextWithVoidCreateMethod { public void create() { } public void whenCreateIsVoid() { whenCreateIsVoid++; } } public class ContextWithoutCreateMethod { public void whenCreateDoesNotExist() { whenCreateDoesNotExist++; } } } public class FailingSpec extends Specification<Void> { public FailingSpec() { throw new RuntimeException(); } public class Context { public void create() { } public void someBehavior() { } } } public static class SpecWithCrashingContextDestroy extends Specification<Void> { public static int onceAfterCalled; private static int specDestroyCalled; public static void onceAfter() { onceAfterCalled++; } public class Context { public void destroy() { throw new RuntimeException("Exception from context destroy"); } public void someBehavior() { } } @Override public void destroy() throws Exception { specDestroyCalled++; } } public static class SpecWithIgnoredContexts extends Specification<Void> { public static List<String> executedContexts = new ArrayList<String>(); public abstract class ContextThatShouldBeIgnored { public void someBehavior() { executedContexts.add(getClass().getSimpleName()); } } class ContextWithDefaultVisibility extends ContextThatShouldBeIgnored { } @Ignore public class ContextWithJUnit4IgnoreAnnotation extends ContextThatShouldBeIgnored { } public class TheOnlyProperContext { public void someBehavior() { } } } }