HHH-5942 - Migrate to JUnit 4

This commit is contained in:
Steve Ebersole 2011-03-17 09:59:34 -05:00
parent 819f8da9ea
commit a4562f4da1
16 changed files with 420 additions and 305 deletions

View File

@ -35,6 +35,10 @@ import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.Stoppable;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.Before;
import org.hibernate.testing.AfterClassOnce;
import org.hibernate.testing.BeforeClassOnce;
import org.hibernate.testing.env.ConnectionProviderBuilder;
/**
@ -46,6 +50,23 @@ public class SuppliedConnectionTest extends ConnectionManagementTestCase {
private ConnectionProvider cp = ConnectionProviderBuilder.buildConnectionProvider();
private Connection connectionUnderTest;
@BeforeClassOnce
private void prepareConnectionProvider() {
cp = ConnectionProviderBuilder.buildConnectionProvider();
}
@AfterClassOnce
private void releaseConnectionProvider() {
try {
if ( cp instanceof Stoppable ) {
( ( Stoppable ) cp ).stop();
}
cp = null;
}
catch( Throwable ignore ) {
}
}
@Override
protected Session getSessionUnderTest() throws Throwable {
connectionUnderTest = cp.getConnection();
@ -131,14 +152,6 @@ public class SuppliedConnectionTest extends ConnectionManagementTestCase {
}
}
}
try {
if ( cp instanceof Stoppable ) {
( ( Stoppable ) cp ).stop();
}
cp = null;
}
catch( Throwable ignore ) {
}
super.cleanupTest();
}
}

View File

@ -71,7 +71,7 @@ public class SQLFunctionsInterSystemsTest extends BaseCoreFunctionalTestCase {
"legacy/AltSimple.hbm.xml",
"legacy/Broken.hbm.xml",
"legacy/Blobber.hbm.xml",
"dialect/cache/TestInterSystemsFunctionsClass.hbm.xml"
"dialect/functional/cache/TestInterSystemsFunctionsClass.hbm.xml"
};
}

View File

@ -2060,6 +2060,8 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
txn.commit();
session.close();
createdAnimalIds.clear();
}
@Test

View File

@ -72,6 +72,8 @@ public class ReadOnlyCriteriaQueryTest extends AbstractReadOnlyTest {
@Test
public void testModifiableSessionDefaultCriteria() {
clearCounts();
Session s = openSession();
Transaction t = s.beginTransaction();

View File

@ -63,7 +63,11 @@ public class RowIdTest extends BaseCoreFunctionalTestCase {
@Override
public void execute(Connection connection) throws SQLException {
Statement st = connection.createStatement();
st.execute( "drop table Point");
try {
st.execute( "drop table Point");
}
catch (Exception ignored) {
}
st.execute("create table Point (\"x\" number(19,2) not null, \"y\" number(19,2) not null, description varchar2(255) )");
st.close();
}

View File

@ -47,10 +47,10 @@ import org.hibernate.usertype.UserType;
* @author Steve Ebersole
*/
public class BasicTypeRegistryTest extends BaseUnitTestCase {
private final BasicTypeRegistry registry = new BasicTypeRegistry();
@Test
public void testOverriding() {
BasicTypeRegistry registry = new BasicTypeRegistry();
BasicType type = registry.getRegisteredType( "uuid-binary" );
assertSame( UUIDBinaryType.INSTANCE, type );
type = registry.getRegisteredType( UUID.class.getName() );
@ -70,6 +70,8 @@ public class BasicTypeRegistryTest extends BaseUnitTestCase {
@Test
public void testExpanding() {
BasicTypeRegistry registry = new BasicTypeRegistry();
BasicType type = registry.getRegisteredType( SomeNoopType.INSTANCE.getName() );
assertNull( type );
@ -81,6 +83,8 @@ public class BasicTypeRegistryTest extends BaseUnitTestCase {
@Test
public void testRegisteringUserTypes() {
BasicTypeRegistry registry = new BasicTypeRegistry();
registry.register( new TotallyIrrelevantUserType(), new String[] { "key" } );
BasicType type = registry.getRegisteredType( "key" );
assertNotNull( type );

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.testing.junit4;
import org.junit.runners.model.Statement;
/**
* @author Steve Ebersole
*/
public class AfterClassCallbackHandler extends Statement {
private final CustomRunner runner;
private final Statement wrappedStatement;
public AfterClassCallbackHandler(CustomRunner runner, Statement wrappedStatement) {
this.runner = runner;
this.wrappedStatement = wrappedStatement;
}
@Override
public void evaluate() throws Throwable {
wrappedStatement.evaluate();
runner.getTestClassMetadata().performAfterClassCallbacks( runner.getTestInstance() );
}
}

View File

@ -43,6 +43,7 @@ import org.hibernate.cfg.Environment;
import org.hibernate.cfg.Mappings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.jdbc.Work;
import org.hibernate.mapping.Collection;
@ -53,7 +54,6 @@ import org.hibernate.service.internal.ServiceRegistryImpl;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.hibernate.testing.AfterClassOnce;
import org.hibernate.testing.BeforeClassOnce;
@ -73,9 +73,9 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
public static final String VALIDATE_DATA_CLEANUP = "hibernate.test.validateDataCleanup";
public static final Dialect DIALECT = Dialect.getDialect();
private static Configuration configuration;
private static ServiceRegistryImpl serviceRegistry;
private static SessionFactoryImplementor sessionFactory;
private Configuration configuration;
private ServiceRegistryImpl serviceRegistry;
private SessionFactoryImplementor sessionFactory;
private org.hibernate.classic.Session session;
@ -317,7 +317,7 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase {
public final void afterTest() throws Exception {
cleanupTest();
if ( session != null && session.isOpen() ) {
if ( session != null && ! ( (SessionImplementor) session ).isClosed() ) {
if ( session.isConnected() ) {
session.doWork( new RollbackWork() );
}

View File

@ -28,22 +28,18 @@ import javax.transaction.SystemException;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.junit.After;
import org.junit.Rule;
import org.junit.runner.RunWith;
import org.hibernate.testing.TestLogger;
import org.hibernate.testing.jta.TestingJtaBootstrap;
/**
* The most test adapter. Applies both the {@link CustomRunner} and {@link Processor} rule.
* The base unit test adapter.
*
* @author Steve Ebersole
*/
@RunWith( CustomRunner.class )
public abstract class BaseUnitTestCase {
@Rule
public Processor processor = new Processor();
@After
public void releaseTransactions() {
if ( JtaStatusHelper.isActive( TestingJtaBootstrap.INSTANCE.getTransactionManager() ) ) {

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.testing.junit4;
import org.junit.runners.model.Statement;
/**
* @author Steve Ebersole
*/
public class BeforeClassCallbackHandler extends Statement {
private final CustomRunner runner;
private final Statement wrappedStatement;
public BeforeClassCallbackHandler(CustomRunner runner, Statement wrappedStatement) {
this.runner = runner;
this.wrappedStatement = wrappedStatement;
}
@Override
public void evaluate() throws Throwable {
runner.getTestClassMetadata().performBeforeClassCallbacks( runner.getTestInstance() );
wrappedStatement.evaluate();
}
}

View File

@ -23,6 +23,7 @@
*/
package org.hibernate.testing.junit4;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
@ -32,12 +33,12 @@ import org.slf4j.LoggerFactory;
import org.hibernate.dialect.Dialect;
import org.hibernate.internal.util.StringHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.runner.manipulation.NoTestsRemainException;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.hibernate.testing.DialectCheck;
import org.hibernate.testing.FailureExpected;
@ -45,7 +46,6 @@ import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.Skip;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.SkipLog;
/**
* The Hibernate-specific {@link org.junit.runner.Runner} implementation which layers {@link ExtendedFrameworkMethod}
@ -53,25 +53,75 @@ import org.hibernate.testing.SkipLog;
* test should be run.
*
* @author Steve Ebersole
* @see Processor
*/
public class CustomRunner extends BlockJUnit4ClassRunner {
private static final Logger log = LoggerFactory.getLogger( CustomRunner.class );
private List<FrameworkMethod> computedTestMethods;
private TestClassMetadata testClassMetadata;
public CustomRunner(Class<?> clazz) throws InitializationError, NoTestsRemainException {
super( clazz );
}
public List<FrameworkMethod> getComputedTestMethods() {
return computedTestMethods;
@Override
protected void collectInitializationErrors(List<Throwable> errors) {
super.collectInitializationErrors( errors );
this.testClassMetadata = new TestClassMetadata( getTestClass().getJavaClass() );
testClassMetadata.validate( errors );
}
public int getNumberOfComputedTestMethods() {
return getComputedTestMethods().size();
public TestClassMetadata getTestClassMetadata() {
return testClassMetadata;
}
@Override
protected Statement withBeforeClasses(Statement statement) {
return new BeforeClassCallbackHandler(
this,
super.withBeforeClasses( statement )
);
}
@Override
protected Statement withAfterClasses(Statement statement) {
return new AfterClassCallbackHandler(
this,
super.withAfterClasses( statement )
);
}
@Override
protected Statement methodInvoker(FrameworkMethod method, final Object test) {
final ExtendedFrameworkMethod extendedFrameworkMethod = (ExtendedFrameworkMethod) method;
final Statement invoker = super.methodInvoker( method, test );
return new TestMethodInvoker( invoker, testClassMetadata, extendedFrameworkMethod, test );
}
public static class FailureExpectedTestPassedException extends Exception {
public FailureExpectedTestPassedException(FrameworkMethod frameworkMethod) {
super( "Test marked as FailureExpected, but did not fail : " + Helper.extractTestName( frameworkMethod ) );
}
}
private Object testInstance;
protected Object getTestInstance() throws Exception {
if ( testInstance == null ) {
testInstance = super.createTest();
}
return testInstance;
}
@Override
protected Object createTest() throws Exception {
return getTestInstance();
}
private List<FrameworkMethod> computedTestMethods;
@Override
protected List<FrameworkMethod> computeTestMethods() {
if ( computedTestMethods == null ) {
@ -80,67 +130,61 @@ public class CustomRunner extends BlockJUnit4ClassRunner {
return computedTestMethods;
}
/**
* Override the JUnit method in order to circumvent the validation check for no matching methods
*/
@Override
protected void validateInstanceMethods(List<Throwable> errors) {
validatePublicVoidNoArgMethods(After.class, false, errors);
validatePublicVoidNoArgMethods(Before.class, false, errors);
validateTestMethods(errors);
computeTestMethods();
if ( !hadAnyTests ) {
errors.add( new Exception( "No runnable methods" ) );
}
}
boolean hadAnyTests;
protected List<FrameworkMethod> doComputation() {
// First, build the callback metadata for the test class...
TestClassCallbackMetadata callbackMetadata = new TestClassCallbackMetadata( getTestClass().getJavaClass() );
// Next, get all the test methods as understood by JUnit
final List<FrameworkMethod> methods = super.computeTestMethods();
hadAnyTests = methods.size() > 0;
// Now process that full list of test methods and build our custom result
final List<FrameworkMethod> result = new ArrayList<FrameworkMethod>();
final boolean doValidation = Boolean.getBoolean( Helper.VALIDATE_FAILURE_EXPECTED );
int testCount = 0;
Ignore virtualIgnore;
for ( FrameworkMethod frameworkMethod : methods ) {
// potentially ignore based on expected failure
final FailureExpected failureExpected = Helper.locateAnnotation( FailureExpected.class, frameworkMethod, getTestClass() );
if ( failureExpected != null && !doValidation ) {
log.info( Helper.extractIgnoreMessage( failureExpected, frameworkMethod ) );
continue;
virtualIgnore = new IgnoreImpl( Helper.extractIgnoreMessage( failureExpected, frameworkMethod ) );
}
// see if the test should be run based on skip/requires annotations
final SkipMarker skipMarker = getSkipInfoIfSkipped( frameworkMethod );
if ( skipMarker != null ) {
SkipLog.reportSkip( skipMarker );
continue;
else {
virtualIgnore = convertSkipToIgnore( frameworkMethod );
}
testCount++;
log.trace( "adding test " + Helper.extractTestName( frameworkMethod ) + " [#" + testCount + "]" );
result.add( new ExtendedFrameworkMethod( frameworkMethod, testCount, skipMarker, failureExpected, callbackMetadata, this ) );
result.add( new ExtendedFrameworkMethod( frameworkMethod, virtualIgnore, failureExpected ) );
}
return result;
}
@SuppressWarnings( {"ClassExplicitlyAnnotation"})
public static class IgnoreImpl implements Ignore {
private final String value;
public IgnoreImpl(String value) {
this.value = value;
}
@Override
public String value() {
return value;
}
@Override
public Class<? extends Annotation> annotationType() {
return Ignore.class;
}
}
private static Dialect dialect = Dialect.getDialect();
protected SkipMarker getSkipInfoIfSkipped(FrameworkMethod frameworkMethod) {
protected Ignore convertSkipToIgnore(FrameworkMethod frameworkMethod) {
// @Skip
Skip skip = Helper.locateAnnotation( Skip.class, frameworkMethod, getTestClass() );
if ( skip != null ) {
if ( isMatch( skip.condition() ) ) {
return buildSkipMarker( skip, frameworkMethod );
return buildIgnore( skip );
}
}
@ -150,12 +194,12 @@ public class CustomRunner extends BlockJUnit4ClassRunner {
for ( Class<? extends Dialect> dialectClass : skipForDialectAnn.value() ) {
if ( skipForDialectAnn.strictMatching() ) {
if ( dialectClass.equals( dialect.getClass() ) ) {
return buildSkipMarker( skipForDialectAnn, frameworkMethod );
return buildIgnore( skipForDialectAnn );
}
}
else {
if ( dialectClass.isInstance( dialect ) ) {
return buildSkipMarker( skipForDialectAnn, frameworkMethod );
return buildIgnore( skipForDialectAnn );
}
}
}
@ -174,7 +218,7 @@ public class CustomRunner extends BlockJUnit4ClassRunner {
}
}
if ( !foundMatch ) {
return buildSkipMarker( requiresDialectAnn, frameworkMethod );
return buildIgnore( requiresDialectAnn );
}
}
@ -185,7 +229,7 @@ public class CustomRunner extends BlockJUnit4ClassRunner {
try {
DialectCheck check = checkClass.newInstance();
if ( !check.isMatch( dialect ) ) {
return buildSkipMarker( requiresDialectFeatureAnn, frameworkMethod );
return buildIgnore( requiresDialectFeatureAnn );
}
}
catch (RuntimeException e) {
@ -199,20 +243,15 @@ public class CustomRunner extends BlockJUnit4ClassRunner {
return null;
}
private SkipMarker buildSkipMarker(Skip skip, FrameworkMethod frameworkMethod) {
return new SkipMarker( Helper.extractTestName( frameworkMethod ), "@Skip : " + skip.message() );
private Ignore buildIgnore(Skip skip) {
return new IgnoreImpl( "@Skip : " + skip.message() );
}
private SkipMarker buildSkipMarker(SkipForDialect skip, FrameworkMethod frameworkMethod) {
return buildSkipMarker(
frameworkMethod,
"@SkipForDialect match",
skip.comment(),
skip.jiraKey()
);
private Ignore buildIgnore(SkipForDialect skip) {
return buildIgnore( "@SkipForDialect match", skip.comment(), skip.jiraKey() );
}
private SkipMarker buildSkipMarker(FrameworkMethod frameworkMethod, String reason, String comment, String jiraKey) {
private Ignore buildIgnore(String reason, String comment, String jiraKey) {
StringBuilder buffer = new StringBuilder( reason );
if ( StringHelper.isNotEmpty( comment ) ) {
buffer.append( "; " ).append( comment );
@ -222,25 +261,15 @@ public class CustomRunner extends BlockJUnit4ClassRunner {
buffer.append( " (" ).append( jiraKey ).append( ')' );
}
return new SkipMarker( Helper.extractTestName( frameworkMethod ), buffer.toString() );
return new IgnoreImpl( buffer.toString() );
}
private SkipMarker buildSkipMarker(RequiresDialect requiresDialect, FrameworkMethod frameworkMethod) {
return buildSkipMarker(
frameworkMethod,
"@RequiresDialect non-match",
requiresDialect.comment(),
requiresDialect.jiraKey()
);
private Ignore buildIgnore(RequiresDialect requiresDialect) {
return buildIgnore( "@RequiresDialect non-match", requiresDialect.comment(), requiresDialect.jiraKey() );
}
private SkipMarker buildSkipMarker(RequiresDialectFeature requiresDialectFeature, FrameworkMethod frameworkMethod) {
return buildSkipMarker(
frameworkMethod,
"@RequiresDialectFeature non-match",
requiresDialectFeature.comment(),
requiresDialectFeature.jiraKey()
);
private Ignore buildIgnore(RequiresDialectFeature requiresDialectFeature) {
return buildIgnore( "@RequiresDialectFeature non-match", requiresDialectFeature.comment(), requiresDialectFeature.jiraKey() );
}
private boolean isMatch(Class<? extends Skip.Matcher> condition) {
@ -258,4 +287,5 @@ public class CustomRunner extends BlockJUnit4ClassRunner {
super( "Unable to instantiate specified Matcher [" + matcherClass.getName(), cause );
}
}
}

View File

@ -23,73 +23,37 @@
*/
package org.hibernate.testing.junit4;
import org.hibernate.testing.FailureExpected;
import org.junit.runners.model.FrameworkMethod;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import org.junit.Ignore;
import org.junit.runners.model.FrameworkMethod;
import org.hibernate.testing.FailureExpected;
/**
* Defines an extension to the standard JUnit {@link FrameworkMethod} information about a test method.
*
* @author Steve Ebersole
*/
public class ExtendedFrameworkMethod extends FrameworkMethod {
private static final Object[] NO_ARGS = new Object[0];
private final FrameworkMethod delegatee;
private final int runPosition;
private final SkipMarker skipMarker;
private final FailureExpected failureExpectedAnnotation;
private final TestClassCallbackMetadata callbackMetadata;
private final CustomRunner unitRunner;
private final Ignore virtualIgnore;
private final FailureExpected failureExpectedAnnotation;
public ExtendedFrameworkMethod(
FrameworkMethod delegatee,
int runPosition,
SkipMarker skipMarker,
FailureExpected failureExpectedAnnotation,
TestClassCallbackMetadata callbackMetadata,
CustomRunner unitRunner) {
public ExtendedFrameworkMethod(FrameworkMethod delegatee, Ignore virtualIgnore, FailureExpected failureExpectedAnnotation) {
super( delegatee.getMethod() );
this.delegatee = delegatee;
this.runPosition = runPosition;
this.skipMarker = skipMarker;
this.virtualIgnore = virtualIgnore;
this.failureExpectedAnnotation = failureExpectedAnnotation;
this.callbackMetadata = callbackMetadata;
this.unitRunner = unitRunner;
}
public CustomRunner getUnitRunner() {
return unitRunner;
public FailureExpected getFailureExpectedAnnotation() {
return failureExpectedAnnotation;
}
public SkipMarker getSkipMarker() {
return skipMarker;
}
public boolean isFirstInTestClass() {
return runPosition == 1;
}
public boolean isLastInTestClass() {
return runPosition >= unitRunner.getNumberOfComputedTestMethods();
}
public boolean isMarkedAsFailureExpected() {
return failureExpectedAnnotation != null;
}
public FailureExpected getFailureExpectedAnnotation() {
return failureExpectedAnnotation;
}
public TestClassCallbackMetadata getCallbackMetadata() {
return callbackMetadata;
}
@Override
@Override
public Method getMethod() {
return delegatee.getMethod();
}
@ -120,6 +84,7 @@ public class ExtendedFrameworkMethod extends FrameworkMethod {
}
@Override
@SuppressWarnings( {"EqualsWhichDoesntCheckParameterClass"})
public boolean equals(Object obj) {
return delegatee.equals( obj );
}
@ -140,7 +105,11 @@ public class ExtendedFrameworkMethod extends FrameworkMethod {
}
@Override
@SuppressWarnings( {"unchecked"})
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
if ( Ignore.class.equals( annotationType ) && virtualIgnore != null ) {
return (T) virtualIgnore;
}
return delegatee.getAnnotation( annotationType );
}
}

View File

@ -91,7 +91,7 @@ public class Helper {
}
public static String extractIgnoreMessage(FailureExpected failureExpected, FrameworkMethod frameworkMethod) {
return new StringBuilder( "Not adding test [" )
return new StringBuilder( "Ignoring test [" )
.append( Helper.extractTestName( frameworkMethod ) )
.append( "] due to @FailureExpected - " )
.append( extractMessage( failureExpected ) )

View File

@ -1,118 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.testing.junit4;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.SkipLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A custom JUnit {@link MethodRule} which essentially acts as "around advice" for test method execution. Works
* in conjunction with the information collected as part of {@link CustomRunner}.
*
* @author Steve Ebersole
* @see CustomRunner
*/
public class Processor implements MethodRule {
private static final Logger log = LoggerFactory.getLogger( Processor.class );
public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object target) {
log.trace( "Preparing to start test {}", Helper.extractTestName( frameworkMethod ) );
if ( ! ExtendedFrameworkMethod.class.isInstance( frameworkMethod ) ) {
throw new IllegalStateException(
"Use of " + getClass().getName() + " only supported in combination with use of "
+ CustomRunner.class.getName()
);
}
final ExtendedFrameworkMethod extendedFrameworkMethod = (ExtendedFrameworkMethod) frameworkMethod;
final SkipMarker skipMarker = extendedFrameworkMethod.getSkipMarker();
if ( skipMarker != null ) {
SkipLog.reportSkip( skipMarker );
return new Statement() {
@Override
public void evaluate() throws Throwable {
}
};
}
final FailureExpected failureExpected = extendedFrameworkMethod.getFailureExpectedAnnotation();
return new Statement() {
@Override
public void evaluate() throws Throwable {
if ( extendedFrameworkMethod.isFirstInTestClass() ) {
extendedFrameworkMethod.getCallbackMetadata().performBeforeClassCallbacks( target );
}
try {
statement.evaluate();
// reaching here is expected, unless the test is marked as an expected failure
if ( failureExpected != null ) {
throw new FailureExpectedTestPassedException( extendedFrameworkMethod );
}
}
catch ( FailureExpectedTestPassedException e ) {
// just pass this along
throw e;
}
catch ( Throwable e ) {
// on error handling is very different based on whether the test was marked as an expected failure
if ( failureExpected != null ) {
// handle the expected failure case
log.info(
"Ignoring expected failure [{}] : {}",
Helper.extractTestName( frameworkMethod ),
Helper.extractMessage( failureExpected )
);
extendedFrameworkMethod.getCallbackMetadata().performOnExpectedFailureCallback( target );
// most importantly, do not propagate exception...
}
else {
// handle the non-expected failure case
extendedFrameworkMethod.getCallbackMetadata().performOnFailureCallback( target );
throw e;
}
}
finally {
if ( extendedFrameworkMethod.isLastInTestClass() ) {
extendedFrameworkMethod.getCallbackMetadata().performAfterClassCallbacks( target );
}
}
}
};
}
public static class FailureExpectedTestPassedException extends Exception {
public FailureExpectedTestPassedException(FrameworkMethod frameworkMethod) {
super( "Test marked as FailureExpected, but did not fail : " + Helper.extractTestName( frameworkMethod ) );
}
}
}

View File

@ -32,13 +32,14 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.List;
/**
* Metadata about various types of callback methods on a given test class.
*
* @author Steve Ebersole
*/
public class TestClassCallbackMetadata {
public class TestClassMetadata {
private static final Object[] NO_ARGS = new Object[0];
private LinkedHashSet<Method> beforeClassOnceMethods;
@ -46,7 +47,7 @@ public class TestClassCallbackMetadata {
private LinkedHashSet<Method> onFailureCallbacks;
private LinkedHashSet<Method> onExpectedFailureCallbacks;
public TestClassCallbackMetadata(Class testClass) {
public TestClassMetadata(Class testClass) {
processClassHierarchy( testClass );
}
@ -73,6 +74,87 @@ public class TestClassCallbackMetadata {
}
}
private void addBeforeClassOnceCallback(Method method) {
if ( beforeClassOnceMethods == null ) {
beforeClassOnceMethods = new LinkedHashSet<Method>();
}
ensureAccessibility( method );
beforeClassOnceMethods.add( method );
}
private void ensureAccessibility(Method method) {
if ( !method.isAccessible() ) {
try {
method.setAccessible( true );
}
catch (Exception ignored) {
// ignore for now
}
}
}
private void addAfterClassOnceCallback(Method method) {
if ( afterClassOnceMethods == null ) {
afterClassOnceMethods = new LinkedHashSet<Method>();
}
ensureAccessibility( method );
afterClassOnceMethods.add( method );
}
private void addOnFailureCallback(Method method) {
if ( onFailureCallbacks == null ) {
onFailureCallbacks = new LinkedHashSet<Method>();
}
ensureAccessibility( method );
onFailureCallbacks.add( method );
}
private void addOnExpectedFailureCallback(Method method) {
if ( onExpectedFailureCallbacks == null ) {
onExpectedFailureCallbacks = new LinkedHashSet<Method>();
}
ensureAccessibility( method );
onExpectedFailureCallbacks.add( method );
}
public void validate(List<Throwable> errors) {
validate( beforeClassOnceMethods, CallbackType.BEFORE_CLASS_ONCE, errors );
validate( afterClassOnceMethods,CallbackType.AFTER_CLASS_ONCE, errors );
validate( onFailureCallbacks, CallbackType.ON_FAILURE, errors );
validate( onExpectedFailureCallbacks, CallbackType.ON_EXPECTED_FAILURE, errors );
}
private void validate(LinkedHashSet<Method> callbackMethods, CallbackType callbackType, List<Throwable> errors) {
if ( callbackMethods != null ) {
for ( Method method : callbackMethods ) {
validateCallbackMethod( method, callbackType, errors );
}
}
}
private void validateCallbackMethod(Method method, CallbackType type, List<Throwable> errors) {
if ( method.getParameterTypes().length > 0 ) {
errors.add(
new InvalidMethodForAnnotationException(
type.buildTypeMarker() + " callback only valid on no-arg methods : "
+ Helper.extractMethodName( method )
)
);
}
if ( !method.isAccessible() ) {
try {
method.setAccessible( true );
}
catch (Exception e) {
errors.add(
new InvalidMethodForAnnotationException(
type.buildTypeMarker() + " attached to inaccessible method and unable to make accessible"
)
);
}
}
}
private static enum CallbackType {
BEFORE_CLASS_ONCE( BeforeClassOnce.class ),
AFTER_CLASS_ONCE( AfterClassOnce.class ),
@ -94,49 +176,6 @@ public class TestClassCallbackMetadata {
}
}
private void addBeforeClassOnceCallback(Method method) {
validateCallbackMethod( method, CallbackType.BEFORE_CLASS_ONCE );
beforeClassOnceMethods = new LinkedHashSet<Method>();
beforeClassOnceMethods.add( method );
}
private void validateCallbackMethod(Method method, CallbackType type) {
if ( method.getParameterTypes().length > 0 ) {
throw new InvalidMethodForAnnotationException(
type.buildTypeMarker() + " callback only valid on no-arg methods : "
+ Helper.extractMethodName( method )
);
}
if ( !method.isAccessible() ) {
try {
method.setAccessible( true );
}
catch (Exception e) {
throw new InvalidMethodForAnnotationException(
type.buildTypeMarker() + " attached to inaccessible method and unable to make accessible"
);
}
}
}
private void addAfterClassOnceCallback(Method method) {
validateCallbackMethod( method, TestClassCallbackMetadata.CallbackType.AFTER_CLASS_ONCE );
afterClassOnceMethods = new LinkedHashSet<Method>();
afterClassOnceMethods.add( method );
}
private void addOnFailureCallback(Method method) {
validateCallbackMethod( method, TestClassCallbackMetadata.CallbackType.ON_FAILURE );
onFailureCallbacks = new LinkedHashSet<Method>();
onFailureCallbacks.add( method );
}
private void addOnExpectedFailureCallback(Method method) {
validateCallbackMethod( method, TestClassCallbackMetadata.CallbackType.ON_EXPECTED_FAILURE );
onExpectedFailureCallbacks = new LinkedHashSet<Method>();
onExpectedFailureCallbacks.add( method );
}
public void performBeforeClassCallbacks(Object target) {
performCallbacks( beforeClassOnceMethods, target );

View File

@ -0,0 +1,84 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.testing.junit4;
import org.junit.runners.model.Statement;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.TestLogger;
/**
* @author Steve Ebersole
*/
class TestMethodInvoker extends Statement {
private final TestClassMetadata testClassMetadata;
private final ExtendedFrameworkMethod extendedFrameworkMethod;
private final Statement realInvoker;
private final Object testInstance;
public TestMethodInvoker(
Statement realInvoker,
TestClassMetadata testClassMetadata,
ExtendedFrameworkMethod extendedFrameworkMethod,
Object testInstance) {
this.realInvoker = realInvoker;
this.testClassMetadata = testClassMetadata;
this.extendedFrameworkMethod = extendedFrameworkMethod;
this.testInstance = testInstance;
}
@Override
public void evaluate() throws Throwable {
final FailureExpected failureExpected = extendedFrameworkMethod.getFailureExpectedAnnotation();
try {
realInvoker.evaluate();
// reaching here is expected, unless the test is marked as an expected failure
if ( failureExpected != null ) {
throw new CustomRunner.FailureExpectedTestPassedException( extendedFrameworkMethod );
}
}
catch (CustomRunner.FailureExpectedTestPassedException e) {
// just pass this along
throw e;
}
catch (Throwable e) {
// on error handling is very different based on whether the test was marked as an expected failure
if ( failureExpected != null ) {
// handle the expected failure case
TestLogger.LOG.infof(
"Ignoring expected failure [{}] : {}",
Helper.extractTestName( extendedFrameworkMethod ),
Helper.extractMessage( failureExpected )
);
testClassMetadata.performOnExpectedFailureCallback( testInstance );
// most importantly, do not propagate exception...
}
else {
// handle the non-expected failure case
testClassMetadata.performOnFailureCallback( testInstance );
throw e;
}
}
}
}