001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.test.context.junit4; 018 019import javax.sql.DataSource; 020 021import org.springframework.beans.factory.annotation.Autowired; 022import org.springframework.context.ApplicationContext; 023import org.springframework.core.io.Resource; 024import org.springframework.dao.DataAccessException; 025import org.springframework.jdbc.core.JdbcTemplate; 026import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; 027import org.springframework.test.context.ContextConfiguration; 028import org.springframework.test.context.TestExecutionListeners; 029import org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener; 030import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 031import org.springframework.test.jdbc.JdbcTestUtils; 032import org.springframework.transaction.PlatformTransactionManager; 033import org.springframework.transaction.annotation.Transactional; 034 035/** 036 * Abstract {@linkplain Transactional transactional} extension of 037 * {@link AbstractJUnit4SpringContextTests} which adds convenience functionality 038 * for JDBC access. Expects a {@link DataSource} bean and a 039 * {@link PlatformTransactionManager} bean to be defined in the Spring 040 * {@linkplain ApplicationContext application context}. 041 * 042 * <p>This class exposes a {@link JdbcTemplate} and provides an easy way to 043 * {@linkplain #countRowsInTable count the number of rows in a table} 044 * (potentially {@linkplain #countRowsInTableWhere with a WHERE clause}), 045 * {@linkplain #deleteFromTables delete from tables}, 046 * {@linkplain #dropTables drop tables}, and 047 * {@linkplain #executeSqlScript execute SQL scripts} within a transaction. 048 * 049 * <p>Concrete subclasses must fulfill the same requirements outlined in 050 * {@link AbstractJUnit4SpringContextTests}. 051 * 052 * <p>The following {@link org.springframework.test.context.TestExecutionListener 053 * TestExecutionListeners} are configured by default: 054 * 055 * <ul> 056 * <li>{@link org.springframework.test.context.web.ServletTestExecutionListener} 057 * <li>{@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener} 058 * <li>{@link org.springframework.test.context.support.DirtiesContextTestExecutionListener} 059 * <li>{@link org.springframework.test.context.transaction.TransactionalTestExecutionListener} 060 * <li>{@link org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener} 061 * </ul> 062 * 063 * <p>This class serves only as a convenience for extension. 064 * <ul> 065 * <li>If you do not wish for your test classes to be tied to a Spring-specific 066 * class hierarchy, you may configure your own custom test classes by using 067 * {@link SpringRunner}, {@link ContextConfiguration @ContextConfiguration}, 068 * {@link TestExecutionListeners @TestExecutionListeners}, etc.</li> 069 * <li>If you wish to extend this class and use a runner other than the 070 * {@link SpringRunner}, as of Spring Framework 4.2 you can use 071 * {@link org.springframework.test.context.junit4.rules.SpringClassRule SpringClassRule} and 072 * {@link org.springframework.test.context.junit4.rules.SpringMethodRule SpringMethodRule} 073 * and specify your runner of choice via {@link org.junit.runner.RunWith @RunWith(...)}.</li> 074 * </ul> 075 * 076 * <p><strong>NOTE:</strong> As of Spring Framework 4.3, this class requires JUnit 4.12 or higher. 077 * 078 * @author Sam Brannen 079 * @author Juergen Hoeller 080 * @since 2.5 081 * @see AbstractJUnit4SpringContextTests 082 * @see org.springframework.test.context.ContextConfiguration 083 * @see org.springframework.test.context.TestExecutionListeners 084 * @see org.springframework.test.context.transaction.TransactionalTestExecutionListener 085 * @see org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener 086 * @see org.springframework.transaction.annotation.Transactional 087 * @see org.springframework.test.annotation.Commit 088 * @see org.springframework.test.annotation.Rollback 089 * @see org.springframework.test.context.transaction.BeforeTransaction 090 * @see org.springframework.test.context.transaction.AfterTransaction 091 * @see org.springframework.test.jdbc.JdbcTestUtils 092 * @see org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests 093 */ 094@TestExecutionListeners({TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class}) 095@Transactional 096public abstract class AbstractTransactionalJUnit4SpringContextTests extends AbstractJUnit4SpringContextTests { 097 098 /** 099 * The {@code JdbcTemplate} that this base class manages, available to subclasses. 100 * @since 3.2 101 */ 102 protected JdbcTemplate jdbcTemplate; 103 104 private String sqlScriptEncoding; 105 106 107 /** 108 * Set the {@code DataSource}, typically provided via Dependency Injection. 109 * <p>This method also instantiates the {@link #jdbcTemplate} instance variable. 110 */ 111 @Autowired 112 public void setDataSource(DataSource dataSource) { 113 this.jdbcTemplate = new JdbcTemplate(dataSource); 114 } 115 116 /** 117 * Specify the encoding for SQL scripts, if different from the platform encoding. 118 * @see #executeSqlScript 119 */ 120 public void setSqlScriptEncoding(String sqlScriptEncoding) { 121 this.sqlScriptEncoding = sqlScriptEncoding; 122 } 123 124 /** 125 * Convenience method for counting the rows in the given table. 126 * @param tableName table name to count rows in 127 * @return the number of rows in the table 128 * @see JdbcTestUtils#countRowsInTable 129 */ 130 protected int countRowsInTable(String tableName) { 131 return JdbcTestUtils.countRowsInTable(this.jdbcTemplate, tableName); 132 } 133 134 /** 135 * Convenience method for counting the rows in the given table, using the 136 * provided {@code WHERE} clause. 137 * <p>See the Javadoc for {@link JdbcTestUtils#countRowsInTableWhere} for details. 138 * @param tableName the name of the table to count rows in 139 * @param whereClause the {@code WHERE} clause to append to the query 140 * @return the number of rows in the table that match the provided 141 * {@code WHERE} clause 142 * @since 3.2 143 * @see JdbcTestUtils#countRowsInTableWhere 144 */ 145 protected int countRowsInTableWhere(String tableName, String whereClause) { 146 return JdbcTestUtils.countRowsInTableWhere(this.jdbcTemplate, tableName, whereClause); 147 } 148 149 /** 150 * Convenience method for deleting all rows from the specified tables. 151 * <p>Use with caution outside of a transaction! 152 * @param names the names of the tables from which to delete 153 * @return the total number of rows deleted from all specified tables 154 * @see JdbcTestUtils#deleteFromTables 155 */ 156 protected int deleteFromTables(String... names) { 157 return JdbcTestUtils.deleteFromTables(this.jdbcTemplate, names); 158 } 159 160 /** 161 * Convenience method for deleting all rows from the given table, using the 162 * provided {@code WHERE} clause. 163 * <p>Use with caution outside of a transaction! 164 * <p>See the Javadoc for {@link JdbcTestUtils#deleteFromTableWhere} for details. 165 * @param tableName the name of the table to delete rows from 166 * @param whereClause the {@code WHERE} clause to append to the query 167 * @param args arguments to bind to the query (leaving it to the {@code 168 * PreparedStatement} to guess the corresponding SQL type); may also contain 169 * {@link org.springframework.jdbc.core.SqlParameterValue SqlParameterValue} 170 * objects which indicate not only the argument value but also the SQL type 171 * and optionally the scale. 172 * @return the number of rows deleted from the table 173 * @since 4.0 174 * @see JdbcTestUtils#deleteFromTableWhere 175 */ 176 protected int deleteFromTableWhere(String tableName, String whereClause, Object... args) { 177 return JdbcTestUtils.deleteFromTableWhere(jdbcTemplate, tableName, whereClause, args); 178 } 179 180 /** 181 * Convenience method for dropping all of the specified tables. 182 * <p>Use with caution outside of a transaction! 183 * @param names the names of the tables to drop 184 * @since 3.2 185 * @see JdbcTestUtils#dropTables 186 */ 187 protected void dropTables(String... names) { 188 JdbcTestUtils.dropTables(this.jdbcTemplate, names); 189 } 190 191 /** 192 * Execute the given SQL script. 193 * <p>Use with caution outside of a transaction! 194 * <p>The script will normally be loaded by classpath. 195 * <p><b>Do not use this method to execute DDL if you expect rollback.</b> 196 * @param sqlResourcePath the Spring resource path for the SQL script 197 * @param continueOnError whether or not to continue without throwing an 198 * exception in the event of an error 199 * @throws DataAccessException if there is an error executing a statement 200 * @see ResourceDatabasePopulator 201 * @see #setSqlScriptEncoding 202 */ 203 protected void executeSqlScript(String sqlResourcePath, boolean continueOnError) throws DataAccessException { 204 Resource resource = this.applicationContext.getResource(sqlResourcePath); 205 new ResourceDatabasePopulator(continueOnError, false, this.sqlScriptEncoding, resource).execute(jdbcTemplate.getDataSource()); 206 } 207 208}