diff --git a/README.md b/README.md index 347c21f..151646a 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Release version contracts-cmdline ----------------- -contracts-cmdline is the model that encompasses the command line tools that will generate reports equivalent ot the maven contracts plugin. +contracts-cmdline is the model that encompasses the command line tools that will generate reports equivalent to the maven contracts plugin. Release version @@ -540,12 +540,28 @@ Indicates that the method is a getter that provides the IProducer to inject or a ContractImpl ------------ -Indentifies the implementation class that is being tested. The argument is the class for which an instance will be created. The __ignore__ property may specify contract tests that should not be executed. +Identifies the implementation class that is being tested. + +ContractImpl has two attributes that can remove tests. + +* skip is an array of interface classes that should not be tested. All contract tests for the interfaces will be skipped. + +* ignore list any @Contract annotated tests that should be ignored. This allows removal of broken +tests that are outside the control of the developer of the @ContractImpl test. + +ContractExclude +--------------- + +ContractExclude is intended to be used with @ContractImpl. The annotation has 2 arguments +1. value is the name of the class that contains the test to exclude. +2. methods is a list of method names in the test class to exclude. + +This annotation will remove the tests only for the ContractImpl it is associated with. ContractTest ------------ -Like a JUnit Test annotation but requries that the test be run within the ContractSuite runner. +Like a JUnit Test annotation but requires that the test be run within the ContractSuite runner. Contract tests may be annotated with the standard JUnit @Ignore annotation to disable the test for all contract suites. Dynamic.Inject -------------- diff --git a/junit/README.md b/junit/README.md index 49a907c..a0d14d2 100644 --- a/junit/README.md +++ b/junit/README.md @@ -4,7 +4,7 @@ junit-contracts: A contract test suite runner A suite runner for use with JUnit @RunWith annotation to run contract tests for interfaces. Handles merging multiple tests from individual contract tests into a single test suite for concrete implementations of one or more interfaces. -Introduces six annotations: +Introduces seven annotations: * @Contract - To map contract tests to the interfaces they test. * @Contract.Inject - To identify the producer of the object under test. @@ -13,6 +13,7 @@ Introduces six annotations: * @Dynamic.Inject - To identify the master producer for dynamic suites. * @NoContractTest - To identify interfaces that should not or do not yet have contract tests. This only applies to interfaces that have methods as pure marker interfaces are automatically ignored. +* @ContractExclude - To exclude specific tests from being executed. Introduces one class @@ -20,7 +21,7 @@ Introduces one class Introduces two interfaces -* Producer - defines a producer that creates new instances of the object under test and can clean up after the test is run. +* IProducer - defines a producer that creates new instances of the object under test and can clean up after the test is run. * Dynamic - defines a dynamic test suite. Dynamic test suites produce a list of tests after the suite is instantiated. Maven Repository Info @@ -66,10 +67,19 @@ The @ContractImpl has two attributes that can remove tests. * ignore list any @Contract annotated tests that should be ignored. This allows removal of broken tests that are outside the control of the developer of the @ContractImpl test. +@ContractExclude +---------------- + +The @ContractExclude annotation is intended to be used with @ContractImpl. The annotation has 2 arguments +1. value is the name of the class that contains the test to exclude. +2. methods is a list of method names in the test class to exclude. + +This annotation will remove the tests only for the ContractImpl it is associated with. + @Contract tests --------------- -The @Contract tests may be removed by adding the standard junit @Ignore annotation. +The @Contract tests may be removed by adding the standard junit @Ignore annotation. This will remove it from all contract testing. diff --git a/junit/src/main/java/org/xenei/junit/contract/ContractExclude.java b/junit/src/main/java/org/xenei/junit/contract/ContractExclude.java new file mode 100644 index 0000000..54aa230 --- /dev/null +++ b/junit/src/main/java/org/xenei/junit/contract/ContractExclude.java @@ -0,0 +1,50 @@ +package org.xenei.junit.contract; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation to exclude specific test methods from the contract suite. + * May be used multiple times. + *

+ * For example + * + *

+ * 
+ * @RunWith( ContractSuite.class )
+ * @ContractImpl( FooImpl.class )
+ * @ContractExclude( ExpertFooTests.class, fns="{barTest,bazTest} )
+ * public class Foo_Test {...}
+ * 
+ *

+ * Declares that in the ExpertFooTests class the + * barTest, and bazTest methods should not + * be executed. + *

+ */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(ContractExcludes.class) +public @interface ContractExclude +{ + /** + * The Contract test implementation (annotated with + * @Contract) that declares the methods that should not be executed. + * + * @return The Contract test class. + */ + Class value(); + + /** + * The list of interface classes for which tests should be skipped. + * This list are interfaces that the class under tests implements but that should + * not be tested. + * + * @return The interfaces to skip testing. + */ + String[] methods(); + +} diff --git a/junit/src/main/java/org/xenei/junit/contract/ContractExcludes.java b/junit/src/main/java/org/xenei/junit/contract/ContractExcludes.java new file mode 100644 index 0000000..57ae10d --- /dev/null +++ b/junit/src/main/java/org/xenei/junit/contract/ContractExcludes.java @@ -0,0 +1,22 @@ +package org.xenei.junit.contract; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The container for repeated ContractExclude annotations. + * + * + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ContractExcludes +{ + /** + * + * The list of ContractExclude annotations. + */ + ContractExclude[] value(); +} diff --git a/junit/src/main/java/org/xenei/junit/contract/ContractImpl.java b/junit/src/main/java/org/xenei/junit/contract/ContractImpl.java index 08f51ca..91de5e7 100644 --- a/junit/src/main/java/org/xenei/junit/contract/ContractImpl.java +++ b/junit/src/main/java/org/xenei/junit/contract/ContractImpl.java @@ -65,14 +65,18 @@ /** * The list of interface classes for which tests should be skipped. + * This list are interfaces that the class under tests implements but that should + * not be tested. * - * @return The interfaces to skip. + * @return The interfaces to skip testing. */ Class[] skip() default {}; /** - * The list of implementations to skip. These are implementations of - * interface tests. + * The list of implementations to skip. + * This list is a list of test implementations that apply to the class under test + * but that should not be executed. This is often + * because the tests are not applicable to this implementation. * * @return the list of interface test implementations to skip. */ diff --git a/junit/src/main/java/org/xenei/junit/contract/ContractSuite.java b/junit/src/main/java/org/xenei/junit/contract/ContractSuite.java index 1cf919f..c701027 100644 --- a/junit/src/main/java/org/xenei/junit/contract/ContractSuite.java +++ b/junit/src/main/java/org/xenei/junit/contract/ContractSuite.java @@ -18,6 +18,7 @@ package org.xenei.junit.contract; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -52,6 +53,7 @@ import org.xenei.junit.contract.info.TestInfo; import org.xenei.junit.contract.info.TestInfoErrorRunner; + /** * Class that runs the Contract annotated tests. * @@ -146,8 +148,6 @@ public ContractSuite(final Class contractTest, final RunnerBuilder builder) * * @param cls * The class to look on - * @param errors - * The list of errors to add to if there is an error * @return ContractImpl or null if not found. * @throws InitializationError */ @@ -161,6 +161,38 @@ private ContractImpl getContractImpl(final Class cls) throws InitializationEr return impl; } + /** + * Get the ContractExclude annotation and extract the list of methods from it. + * + * logs error if method is not found on the class specified in the annotation. + * + * @param cls + * The class on which to for the annotation. + * @param errors + * The list of errors to add to if there is an error + * @return A list of methods. May be empty. + * @throws InitializationError + */ + private List getExcludedMethods(final Class cls) { + + List lst = new ArrayList(); + for (ContractExclude exclude : cls.getAnnotationsByType(ContractExclude.class)) + { + Class clazz = exclude.value(); + for (String mthdName : exclude.methods()) + { + try + { + lst.add(clazz.getDeclaredMethod(mthdName)); + } catch (NoSuchMethodException | SecurityException e) + { + LOG.warn( String.format( "ContractExclude annotation on %s incorrect", cls), e); + } + } + } + return lst; + } + /** * Add dynamic classes to the suite. * @@ -283,17 +315,20 @@ private List addAnnotatedClasses(final Class baseClass, final RunnerB private void addSpecifiedClasses(final List runners, final Class testClass, final RunnerBuilder builder, final ContractTestMap contractTestMap, final Object baseObj, final TestInfo parentTestInfo) throws InitializationError { + + // this is the list of all the JUnit runners in the suite. - final Set testClasses = new LinkedHashSet(); + // we have a RunWith annotated class: Klass // see if it is in the annotatedClasses - final BaseClassRunner bcr = new BaseClassRunner(testClass); if (bcr.computeTestMethods().size() > 0) { runners.add(bcr); } + List excludeMethods = getExcludedMethods(getTestClass().getJavaClass()); + /* * get all the annotated classes that test the interfaces that * parentTestInfo implements and iterate over them @@ -308,7 +343,7 @@ private void addSpecifiedClasses(final List runners, final Class test runner.logErrors(LOG); runners.add(runner); } else { - runners.add(new ContractTestRunner(baseObj, parentTestInfo, testInfo)); + runners.add(new ContractTestRunner(baseObj, parentTestInfo, testInfo, excludeMethods)); } } } @@ -341,9 +376,9 @@ protected void runChild(final Runner child, final RunNotifier notifier) { private class BaseClassRunner extends BlockJUnit4ClassRunner { private List testMethods = null; - + public BaseClassRunner(final Class cls) throws InitializationError { - super(cls); + super(cls); } @Override @@ -367,8 +402,10 @@ protected void validateInstanceMethods(final List errors) { protected List computeTestMethods() { if (testMethods == null) { testMethods = new ArrayList(); + List excludeMethods = getExcludedMethods(getTestClass().getJavaClass()); for (final FrameworkMethod mthd : super.getTestClass().getAnnotatedMethods(ContractTest.class)) { - if (mthd.getMethod().getDeclaringClass().getAnnotation(Contract.class) == null) { + if (mthd.getMethod().getDeclaringClass().getAnnotation(Contract.class) == null && + ! excludeMethods.contains(mthd.getMethod())) { testMethods.add(mthd); } } diff --git a/junit/src/main/java/org/xenei/junit/contract/ContractTestRunner.java b/junit/src/main/java/org/xenei/junit/contract/ContractTestRunner.java index 0edb9b4..ef3c5fb 100644 --- a/junit/src/main/java/org/xenei/junit/contract/ContractTestRunner.java +++ b/junit/src/main/java/org/xenei/junit/contract/ContractTestRunner.java @@ -20,9 +20,13 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import org.junit.Ignore; import org.junit.runner.Description; +import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; @@ -43,6 +47,7 @@ public class ContractTestRunner extends BlockJUnit4ClassRunner { private final Object getterObj; // the getter method to call. private final Method getter; + private final List excludedMethods; /** * Create a test runner within the ContractTestSuite. @@ -54,24 +59,29 @@ public class ContractTestRunner extends BlockJUnit4ClassRunner { * The test info for the parent. * @param testInfo * The test info for this test. + * @param excludedMethods + * A list of test methods that should not be executed. * * @throws InitializationError * on error. */ public ContractTestRunner(Object getterObj, TestInfo parentTestInfo, - TestInfo testInfo) throws InitializationError { + TestInfo testInfo, List excludedMethods) throws InitializationError { super(testInfo.getContractTestClass()); this.parentTestInfo = parentTestInfo; this.testInfo = testInfo; this.getterObj = getterObj; this.getter = parentTestInfo.getMethod(); + this.excludedMethods = excludedMethods; } /** * Create a test runner for stand alone test * * @param testClass - * The ContractTest annoated class. + * The ContractTest annotated class. + * @param excludedMethods + * A list of test methods that should not be executed. * * @throws InitializationError * on error. @@ -82,6 +92,7 @@ public ContractTestRunner(Class testClass) throws InitializationError { this.testInfo = null; this.getterObj = null; this.getter = null; + this.excludedMethods = Collections.emptyList(); } /** @@ -117,6 +128,16 @@ protected Object createTest() throws InstantiationException, return retval; } + + @Override + protected void runChild(final FrameworkMethod method, RunNotifier notifier) { + Description description = describeChild(method); + if (method.getAnnotation(Ignore.class) != null || excludedMethods.contains( method.getMethod())) { + notifier.fireTestIgnored(description); + } else { + runLeaf(methodBlock(method), description, notifier); + } + } /** * Adds to {@code errors} if the test class has more than one constructor, @@ -161,8 +182,13 @@ protected Description describeChild(FrameworkMethod method) { */ @Override protected List computeTestMethods() { - // this is call during construction. testInfo is not yet available. + // this is call during construction. testInfo and excludedMethods is not yet available. return getTestClass().getAnnotatedMethods(ContractTest.class); } + + @Override + public String toString() { + return "ContractTest"+testInfo==null?"":testInfo.toString(); + } } diff --git a/junit/src/main/java/org/xenei/junit/contract/info/ContractTestMap.java b/junit/src/main/java/org/xenei/junit/contract/info/ContractTestMap.java index b48449f..e563391 100644 --- a/junit/src/main/java/org/xenei/junit/contract/info/ContractTestMap.java +++ b/junit/src/main/java/org/xenei/junit/contract/info/ContractTestMap.java @@ -52,19 +52,6 @@ public class ContractTestMap { private static final Log LOG = LogFactory.getLog(ContractTestMap.class); - /** - * Create an instance of ContractTestMap using the specified class loader. - * - * Contract tests must be annotated with @Contract and must not be annotated - * with @Ignore - * - * @param classLoader - * The class loader to use. - * @param packages - * A list of package names to report - * @return A ContractTestMap. - */ - /** * Constructor * diff --git a/junit/src/main/java/org/xenei/junit/contract/info/TestInfo.java b/junit/src/main/java/org/xenei/junit/contract/info/TestInfo.java index 701b482..aebb404 100644 --- a/junit/src/main/java/org/xenei/junit/contract/info/TestInfo.java +++ b/junit/src/main/java/org/xenei/junit/contract/info/TestInfo.java @@ -140,7 +140,7 @@ public Class[] getSkipTests() { } /** - * Get the package name of the cla under test.. + * Get the package name of the class under test.. * * @return The contract class package name. */ diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/B.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/B.java index 4b70a91..a3d1003 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/B.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/B.java @@ -26,8 +26,12 @@ public interface B { /** * - * @return the B Bane + * @return the B name; */ public String getBName(); + /** + * @return the B int + */ + public int getBInt(); } diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImpl.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImpl.java index 173b3d7..117821c 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImpl.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImpl.java @@ -33,4 +33,12 @@ public String getBName() { public String toString() { return "BImpl"; } + + @Override + public int getBInt() + { + return 1; + } + + } diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImplContractTest.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImplContractTest.java index 703e36f..4bce74f 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImplContractTest.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImplContractTest.java @@ -95,7 +95,9 @@ public static void beforeClass() { @AfterClass public static void afterClass() { String[] expected = { "BImplContractTest.producer.newInstance()", - "bname", "BImplContractTest.producer.cleanUp()" }; + "bname", "BImplContractTest.producer.cleanUp()", + "BImplContractTest.producer.newInstance()", + "BInt=1", "BImplContractTest.producer.cleanUp()" }; List l = Listener.get(); Assert.assertEquals(l, Arrays.asList(expected)); diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImplTest.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImplTest.java index 1892942..9db62b9 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImplTest.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/BImplTest.java @@ -78,7 +78,9 @@ public static void beforeClass() { @AfterClass public static void afterClass() { String[] expected = { "BImplTest.producer.newInstance()", "bname", - "BImplTest.producer.cleanUp()" }; + "BImplTest.producer.cleanUp()", + "BImplTest.producer.newInstance()", + "BInt=1", "BImplTest.producer.cleanUp()" }; List l = Listener.get(); Assert.assertEquals(l, Arrays.asList(expected)); diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/BT.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/BT.java index e0d8b22..60c6cdc 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/BT.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/BT.java @@ -68,6 +68,14 @@ public void testGetBName() { Listener.add(getProducer().newInstance().getBName()); } + /** + * Test getBInt() + */ + @ContractTest + public void testGetBInt() { + Listener.add( "BInt="+getProducer().newInstance().getBInt()); + } + /** * Clean up the producer. */ diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl.java index 0ce79f0..8ac26ee 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl.java @@ -42,4 +42,11 @@ public String getBName() { public String toString() { return "CImpl"; } + + @Override + public int getBInt() + { + return 2; + } + } diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl2.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl2.java index 04506ad..b1c60c5 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl2.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl2.java @@ -42,6 +42,13 @@ public String getBName() { public String toString() { return "CImpl2"; } + + @Override + public int getBInt() + { + return 3; + } + /** * An extra method in this implementation that is not defined in C. diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl2ContractTest.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl2ContractTest.java index becbd1c..dddfb1d 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl2ContractTest.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl2ContractTest.java @@ -106,7 +106,7 @@ public static void beforeClass() { private static void verifyTest( List expectedTests, List results) { Assert.assertEquals( "CImpl2ContractTest.producer.newInstance()", results.get(0)); - Assert.assertTrue( expectedTests.contains( results.get(1))); + Assert.assertTrue( "Missing "+results.get(1), expectedTests.contains( results.get(1))); expectedTests.remove( results.get(1)); Assert.assertEquals( "CImpl2ContractTest.producer.cleanUp()", results.get(2)); @@ -116,7 +116,7 @@ private static void verifyTest( List expectedTests, List results */ @AfterClass public static void afterClass() { - final String[] testNames = {"called Extra Method","cname", "cname version of aname", "cname version of bname" }; + final String[] testNames = {"called Extra Method","cname", "cname version of aname", "BInt=3", "cname version of bname" }; final List expectedTests = new ArrayList(Arrays.asList(testNames)); @@ -127,7 +127,7 @@ public static void afterClass() { int j = i*3; verifyTest( expectedTests, l.subList(j, j+3)); } - + Assert.assertTrue( expectedTests.isEmpty()); } } diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl3.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl3.java index fc6e37d..d93163c 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl3.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImpl3.java @@ -28,4 +28,10 @@ public String getBName() { return null; } + @Override + public int getBInt() + { + return 4; + } + } diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImplContractTest.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImplContractTest.java index cc99987..c57bef7 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImplContractTest.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImplContractTest.java @@ -87,7 +87,7 @@ public static void beforeClass() { private static void verifyTest( List expectedTests, List results) { Assert.assertEquals( "CImplContractTest.producer.newInstance()", results.get(0)); - Assert.assertTrue( expectedTests.contains( results.get(1))); + Assert.assertTrue( "Missing "+results.get(1), expectedTests.contains( results.get(1))); expectedTests.remove( results.get(1)); Assert.assertEquals( "CImplContractTest.producer.cleanUp()", results.get(2)); @@ -97,7 +97,7 @@ private static void verifyTest( List expectedTests, List results */ @AfterClass public static void afterClass() { - final String[] testNames = {"cname", "cname version of aname", "cname version of bname" }; + final String[] testNames = {"cname", "cname version of aname", "cname version of bname", "BInt=2" }; final List expectedTests = new ArrayList(Arrays.asList(testNames)); @@ -108,7 +108,8 @@ public static void afterClass() { int j = i*3; verifyTest( expectedTests, l.subList(j, j+3)); } - + Assert.assertTrue( expectedTests.isEmpty() ); + } diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImplContractTestWithExclude.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImplContractTestWithExclude.java new file mode 100644 index 0000000..8bde73e --- /dev/null +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/CImplContractTestWithExclude.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.xenei.junit.contract.exampleTests; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; +import org.xenei.junit.bad.BadNoInject; +import org.xenei.junit.contract.Contract; +import org.xenei.junit.contract.ContractExclude; +import org.xenei.junit.contract.ContractImpl; +import org.xenei.junit.contract.ContractSuite; +import org.xenei.junit.contract.IProducer; + +/** + * Run the C tests using the contract suite runner. + * + * This will run the tests defined in CT as well as AT (A contract tests) and BT + * (B contract tests). Compare this to CImplTest. + * + * Note that producer used for the AT and BT classes will be the + * IProducer<CImpl$gt; from this class. + * + * The use of the Listener interface in the before and after methods are to + * track that the tests are run correctly and in the proper order. This would + * not be used in a production test but are part of our testing of + * junit-contracts. + * + */ +// run as a contract test +@RunWith(ContractSuite.class) +// testing the CImpl class. +@ContractImpl( value=CImpl.class, ignore = { BadNoInject.class }) +@ContractExclude( value=BT.class, methods={"testGetBInt"}) +public class CImplContractTestWithExclude { + // the producer to use for all the tests + private IProducer producer = new IProducer() { + @Override + public CImpl newInstance() { + Listener.add("CImplContractTest.producer.newInstance()"); + return new CImpl(); + } + + @Override + public void cleanUp() { + Listener.add("CImplContractTest.producer.cleanUp()"); + } + }; + + /** + * The method to inject the producer into the test classes. + * + * @return The producer we want to use for the tests. + */ + @Contract.Inject + public IProducer getProducer() { + return producer; + } + + /** + * Clean up the listener for the tests. + */ + @BeforeClass + public static void beforeClass() { + Listener.clear(); + } + + private static void verifyTest( List expectedTests, List results) { + Assert.assertEquals( "CImplContractTest.producer.newInstance()", results.get(0)); + Assert.assertTrue( "Missing "+results.get(1), expectedTests.contains( results.get(1))); + expectedTests.remove( results.get(1)); + Assert.assertEquals( "CImplContractTest.producer.cleanUp()", results.get(2)); + + } + /** + * Verify that the Listener recorded all the expected events. + */ + @AfterClass + public static void afterClass() { + final String[] testNames = {"cname", "cname version of bname", "cname version of aname" }; + final List expectedTests = new ArrayList(Arrays.asList(testNames)); + + + final List l = Listener.get(); + + for (int i=0;i expectedTests, List results) { Assert.assertEquals( "CImplContractTest.producer.newInstance()", results.get(0)); - Assert.assertTrue( expectedTests.contains( results.get(1))); + Assert.assertTrue( "Missing "+results.get(1), expectedTests.contains( results.get(1))); expectedTests.remove( results.get(1)); Assert.assertEquals( "CImplContractTest.producer.cleanUp()", results.get(2)); @@ -95,7 +95,7 @@ private static void verifyTest( List expectedTests, List results */ @AfterClass public static void afterClass() { - final String[] testNames = {"cname", "cname version of bname" }; + final String[] testNames = {"cname", "cname version of bname", "BInt=2" }; final List expectedTests = new ArrayList(Arrays.asList(testNames)); @@ -106,7 +106,7 @@ public static void afterClass() { int j = i*3; verifyTest( expectedTests, l.subList(j, j+3)); } - + Assert.assertTrue( expectedTests.isEmpty() ); } } diff --git a/junit/src/test/java/org/xenei/junit/contract/exampleTests/FImpl.java b/junit/src/test/java/org/xenei/junit/contract/exampleTests/FImpl.java index 2ac2386..03b92dc 100644 --- a/junit/src/test/java/org/xenei/junit/contract/exampleTests/FImpl.java +++ b/junit/src/test/java/org/xenei/junit/contract/exampleTests/FImpl.java @@ -32,4 +32,10 @@ public String getFName() { return null; } + @Override + public int getBInt() + { + return 5; + } + }