提交 677a3215 编写于 作者: S Sam Brannen

Support primary TxMgrs and DataSources in the TCF

Prior to this commit, the transaction manager and data source look-up
algorithms in the Spring TestContext Framework were not capable of
retrieving 'primary' beans of those types, even though 'primary' beans
are supported in production as well as for injecting dependencies into
test instances. Specifically, if there was more than one transaction
manager or data source bean and one of them was flagged as 'primary',
the retrieveTransactionManager() and retrieveDataSource() methods in
TestContextTransactionUtils would simply return null for such beans.

This commit updates TestContextTransactionUtils by adding support for
looking up primary transaction managers and data sources.

Issue: SPR-13891
上级 6d2b9a01
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
......@@ -17,6 +17,7 @@
package org.springframework.test.context.transaction;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
......@@ -73,7 +74,8 @@ public abstract class TestContextTransactionUtils {
* <li>Look up the {@code DataSource} by type and name, if the supplied
* {@code name} is non-empty, throwing a {@link BeansException} if the named
* {@code DataSource} does not exist.
* <li>Attempt to look up a single {@code DataSource} by type.
* <li>Attempt to look up the single {@code DataSource} by type.
* <li>Attempt to look up the <em>primary</em> {@code DataSource} by type.
* <li>Attempt to look up the {@code DataSource} by type and the
* {@linkplain #DEFAULT_DATA_SOURCE_NAME default data source name}.
* @param testContext the test context for which the {@code DataSource}
......@@ -110,15 +112,21 @@ public abstract class TestContextTransactionUtils {
if (dataSources.size() == 1) {
return dataSources.values().iterator().next();
}
try {
// look up single bean by type, with support for 'primary' beans
return bf.getBean(DataSource.class);
}
catch (BeansException ex) {
logBeansException(testContext, ex, PlatformTransactionManager.class);
}
}
// look up by type and default name
return bf.getBean(DEFAULT_DATA_SOURCE_NAME, DataSource.class);
}
catch (BeansException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Caught exception while retrieving DataSource for test context " + testContext, ex);
}
logBeansException(testContext, ex, DataSource.class);
return null;
}
}
......@@ -133,7 +141,8 @@ public abstract class TestContextTransactionUtils {
* <li>Look up the transaction manager by type and explicit name, if the supplied
* {@code name} is non-empty, throwing a {@link BeansException} if the named
* transaction manager does not exist.
* <li>Attempt to look up the transaction manager by type.
* <li>Attempt to look up the single transaction manager by type.
* <li>Attempt to look up the <em>primary</em> transaction manager by type.
* <li>Attempt to look up the transaction manager via a
* {@link TransactionManagementConfigurer}, if present.
* <li>Attempt to look up the transaction manager by type and the
......@@ -176,6 +185,14 @@ public abstract class TestContextTransactionUtils {
return txMgrs.values().iterator().next();
}
try {
// look up single bean by type, with support for 'primary' beans
return bf.getBean(PlatformTransactionManager.class);
}
catch (BeansException ex) {
logBeansException(testContext, ex, PlatformTransactionManager.class);
}
// look up single TransactionManagementConfigurer
Map<String, TransactionManagementConfigurer> configurers = BeanFactoryUtils.beansOfTypeIncludingAncestors(
lbf, TransactionManagementConfigurer.class);
......@@ -192,14 +209,18 @@ public abstract class TestContextTransactionUtils {
return bf.getBean(DEFAULT_TRANSACTION_MANAGER_NAME, PlatformTransactionManager.class);
}
catch (BeansException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Caught exception while retrieving transaction manager for test context " + testContext,
ex);
}
logBeansException(testContext, ex, PlatformTransactionManager.class);
return null;
}
}
private static void logBeansException(TestContext testContext, BeansException ex, Class<?> beanType) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Caught exception while retrieving %s for test context %s",
beanType.getSimpleName(), testContext), ex);
}
}
/**
* Create a delegating {@link TransactionAttribute} for the supplied target
* {@link TransactionAttribute} and {@link TestContext}, using the names of
......
/*
* Copyright 2002-2016 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.context.jdbc;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.jdbc.JdbcTestUtils;
import org.springframework.test.transaction.TransactionTestUtils;
import static org.junit.Assert.*;
/**
* Integration tests that ensure that <em>primary</em> data sources are
* supported.
*
* @author Sam Brannen
* @since 4.3
* @see org.springframework.test.context.transaction.PrimaryTransactionManagerTests
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext
public class PrimaryDataSourceTests {
@Configuration
static class Config {
@Primary
@Bean
public DataSource primaryDataSource() {
// @formatter:off
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.addScript("classpath:/org/springframework/test/context/jdbc/schema.sql")
.build();
// @formatter:on
}
@Bean
public DataSource additionalDataSource() {
return new EmbeddedDatabaseBuilder().generateUniqueName(true).build();
}
}
private JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Test
@Sql("data.sql")
public void dataSourceTest() {
TransactionTestUtils.assertInTransaction(false);
assertEquals("Number of rows in the 'user' table.", 1,
JdbcTestUtils.countRowsInTable(this.jdbcTemplate, "user"));
}
}
/*
* Copyright 2002-2016 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.context.transaction;
import javax.sql.DataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.jdbc.JdbcTestUtils;
import org.springframework.test.transaction.TransactionTestUtils;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.Assert.*;
/**
* Integration tests that ensure that <em>primary</em> transaction managers
* are supported.
*
* @author Sam Brannen
* @since 4.3
* @see org.springframework.test.context.jdbc.PrimaryDataSourceTests
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext
public class PrimaryTransactionManagerTests {
@Configuration
static class Config {
@Primary
@Bean
public PlatformTransactionManager primaryTransactionManager() {
return new DataSourceTransactionManager(dataSource1());
}
@Bean
public PlatformTransactionManager additionalTransactionManager() {
return new DataSourceTransactionManager(dataSource2());
}
@Bean
public DataSource dataSource1() {
// @formatter:off
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.addScript("classpath:/org/springframework/test/context/jdbc/schema.sql")
.build();
// @formatter:on
}
@Bean
public DataSource dataSource2() {
return new EmbeddedDatabaseBuilder().generateUniqueName(true).build();
}
}
private JdbcTemplate jdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource1) {
this.jdbcTemplate = new JdbcTemplate(dataSource1);
}
@BeforeTransaction
public void beforeTransaction() {
assertNumUsers(0);
}
@Test
@Transactional
public void transactionalTest() {
TransactionTestUtils.assertInTransaction(true);
ClassPathResource resource = new ClassPathResource("/org/springframework/test/context/jdbc/data.sql");
new ResourceDatabasePopulator(resource).execute(jdbcTemplate.getDataSource());
assertNumUsers(1);
}
@AfterTransaction
public void afterTransaction() {
assertNumUsers(0);
}
private void assertNumUsers(int expected) {
assertEquals("Number of rows in the 'user' table.", expected,
JdbcTestUtils.countRowsInTable(this.jdbcTemplate, "user"));
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册