⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abstractannotationawaretransactionaltests.java

📁 Spring API核心源代码 Spring API核心源代码 Spring API核心源代码
💻 JAVA
字号:
/*
 * Copyright 2002-2007 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 org.springframework.test.annotation;

import java.lang.reflect.Method;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;

import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionAttributeSource;

/**
 * Java 5 specific subclass of
 * {@link AbstractTransactionalDataSourceSpringContextTests}, exposing a
 * {@link SimpleJdbcTemplate} and obeying annotations for transaction control.
 *
 * <p>For example, test methods can be annotated with the regular Spring
 * {@link org.springframework.transaction.annotation.Transactional} annotation
 * (for example, to force execution in a read-only transaction) or with the
 * {@link NotTransactional} annotation to prevent any transaction being created
 * at all.
 *
 * @author Rod Johnson
 * @since 2.0
 */
public abstract class AbstractAnnotationAwareTransactionalTests
		extends AbstractTransactionalDataSourceSpringContextTests {
	
	protected SimpleJdbcTemplate simpleJdbcTemplate;
	
	private TransactionAttributeSource transactionAttributeSource = new AnnotationTransactionAttributeSource();
	
	protected ProfileValueSource profileValueSource = SystemProfileValueSource.getInstance();


	@Override
	public void setDataSource(DataSource dataSource) {
		super.setDataSource(dataSource);
		// JdbcTemplate will be identically configured
		this.simpleJdbcTemplate = new SimpleJdbcTemplate(this.jdbcTemplate);
	}

	// TODO code to try to load (and cache!) ProfileValueSource
	// from a given URL? It's easy enough to do, of course.
	protected void findUniqueProfileValueSourceFromContext(ApplicationContext ac) {
		Map beans = ac.getBeansOfType(ProfileValueSource.class);
		if (beans.size() == 1) {
			this.profileValueSource = (ProfileValueSource) beans.values().iterator().next();
		}
	}


	/**
	 * Overridden to populate transaction definition from annotations.
	 */
	@Override
	public void runBare() throws Throwable {
		// getName will return the name of the method being run.
		if (isDisabledInThisEnvironment(getName())) {
			// Let superclass log that we didn't run the test.
			super.runBare();
			return;
		}
		
		// Use same algorithm as JUnit itself to retrieve the test method
		// about to be executed (the method name is returned by getName).
		// It has to be public so we can retrieve it
		final Method testMethod = getClass().getMethod(getName(), (Class[]) null);
		
		if (isDisabledInThisEnvironment(testMethod)) {
			logger.info("**** " + getClass().getName() + "." + getName() + " disabled in this environment: " +
					"Total disabled tests=" + getDisabledTestCount());
			recordDisabled();
			return;
		} 
		
		TransactionDefinition explicitTransactionDefinition =
				this.transactionAttributeSource.getTransactionAttribute(testMethod, getClass());
		if (explicitTransactionDefinition != null) {
			logger.info("Custom transaction definition [" + explicitTransactionDefinition + " for test method " + getName());
			setTransactionDefinition(explicitTransactionDefinition);
		}
		else if (testMethod.isAnnotationPresent(NotTransactional.class)) {
			// Don't have any transaction...
			preventTransaction();
		}
		
		// Let JUnit handle execution. We're just changing the state of the
		// test class first.
		runTestTimed(
				new TestExecutionCallback() {
					public void run() throws Throwable {
						try {
							AbstractAnnotationAwareTransactionalTests.super.runBare();
						}
						finally {
							// Mark the context to be blown
							// away if the test was annotated to result
							// in setDirty being invoked automatically
							if (testMethod.isAnnotationPresent(DirtiesContext.class)) {
								AbstractAnnotationAwareTransactionalTests.this.setDirty();
							}
						}
					}
				},
				testMethod,
				logger);
	}

	protected boolean isDisabledInThisEnvironment(Method testMethod) {
		IfProfileValue inProfile = testMethod.getAnnotation(IfProfileValue.class);
		if (inProfile == null) {
			inProfile = getClass().getAnnotation(IfProfileValue.class);
		}

		if (inProfile != null) {
			// May be true
			return !this.profileValueSource.get(inProfile.name()).equals(inProfile.value());
		}
		else {
			return false;
		}

		// TODO IfNotProfileValue
	}


	private static void runTestTimed(TestExecutionCallback tec, Method testMethod, Log logger) throws Throwable {
		Timed timed = testMethod.getAnnotation(Timed.class);
		
		if (timed == null) {
			runTest(tec, testMethod, logger);
		}
		else {
			long startTime = System.currentTimeMillis();
			try {
				runTest(tec, testMethod, logger);
			}
			finally {
				long elapsed = System.currentTimeMillis() - startTime;
				if (elapsed > timed.millis()) {
					fail("Took " + elapsed + " ms; limit was " + timed.millis());
				}
			}
		}
	}
	
	private static void runTest(TestExecutionCallback tec, Method testMethod, Log logger) throws Throwable {
		ExpectedException ee = testMethod.getAnnotation(ExpectedException.class);
		Repeat repeat = testMethod.getAnnotation(Repeat.class);
		
		int runs = (repeat != null) ? repeat.value() : 1;
		
		for (int i = 0; i < runs; i++) {
			try {
				if (i > 0 && logger != null) {
					logger.info("Repetition " + i + " of test " + testMethod.getName());
				}
				tec.run();
				if (ee != null) {
					fail("Expected throwable of class " + ee.value());
				}
			}
			catch (Throwable t) {
				if (ee == null) {
					throw t;
				}
				if (ee.value().isAssignableFrom(t.getClass())) {
					// Ok
				}
				else {
					//fail("Expected throwable of class " + ee.value() + "; got " + t);
					// Throw the unexpected problem throwable
					throw t;
				}
			}
		}
	}


	private static interface TestExecutionCallback {

		void run() throws Throwable;
	}

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -