001/* 002 * Copyright 2002-2019 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.testng; 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.lang.Nullable; 028import org.springframework.test.context.TestExecutionListeners; 029import org.springframework.test.context.event.EventPublishingTestExecutionListener; 030import org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener; 031import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; 032import org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener; 033import org.springframework.test.context.support.DirtiesContextTestExecutionListener; 034import org.springframework.test.context.transaction.TransactionalTestExecutionListener; 035import org.springframework.test.context.web.ServletTestExecutionListener; 036import org.springframework.test.jdbc.JdbcTestUtils; 037import org.springframework.transaction.PlatformTransactionManager; 038import org.springframework.transaction.annotation.Transactional; 039import org.springframework.util.Assert; 040 041/** 042 * Abstract {@linkplain Transactional transactional} extension of 043 * {@link AbstractTestNGSpringContextTests} which adds convenience functionality 044 * for JDBC access. Expects a {@link DataSource} bean and a 045 * {@link PlatformTransactionManager} bean to be defined in the Spring 046 * {@linkplain ApplicationContext application context}. 047 * 048 * <p>This class exposes a {@link JdbcTemplate} and provides an easy way to 049 * {@linkplain #countRowsInTable count the number of rows in a table} 050 * (potentially {@linkplain #countRowsInTableWhere with a WHERE clause}), 051 * {@linkplain #deleteFromTables delete from tables}, 052 * {@linkplain #dropTables drop tables}, and 053 * {@linkplain #executeSqlScript execute SQL scripts} within a transaction. 054 * 055 * <p>Concrete subclasses must fulfill the same requirements outlined in 056 * {@link AbstractTestNGSpringContextTests}. 057 * 058 * <p>The following {@link org.springframework.test.context.TestExecutionListener 059 * TestExecutionListeners} are configured by default: 060 * 061 * <ul> 062 * <li>{@link org.springframework.test.context.web.ServletTestExecutionListener} 063 * <li>{@link org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener} 064 * <li>{@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener} 065 * <li>{@link org.springframework.test.context.support.DirtiesContextTestExecutionListener} 066 * <li>{@link org.springframework.test.context.transaction.TransactionalTestExecutionListener} 067 * <li>{@link org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener} 068 * <li>{@link org.springframework.test.context.event.EventPublishingTestExecutionListener} 069 * </ul> 070 * 071 * @author Sam Brannen 072 * @author Juergen Hoeller 073 * @since 2.5 074 * @see AbstractTestNGSpringContextTests 075 * @see org.springframework.test.context.ContextConfiguration 076 * @see org.springframework.test.context.TestExecutionListeners 077 * @see org.springframework.test.context.transaction.TransactionalTestExecutionListener 078 * @see org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener 079 * @see org.springframework.transaction.annotation.Transactional 080 * @see org.springframework.test.annotation.Commit 081 * @see org.springframework.test.annotation.Rollback 082 * @see org.springframework.test.context.transaction.BeforeTransaction 083 * @see org.springframework.test.context.transaction.AfterTransaction 084 * @see org.springframework.test.jdbc.JdbcTestUtils 085 * @see org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests 086 */ 087@TestExecutionListeners(listeners = { ServletTestExecutionListener.class, 088 DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, 089 DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class, 090 SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class }, inheritListeners = false) 091@Transactional 092public abstract class AbstractTransactionalTestNGSpringContextTests extends AbstractTestNGSpringContextTests { 093 094 /** 095 * The {@code JdbcTemplate} that this base class manages, available to subclasses. 096 * @since 3.2 097 */ 098 protected final JdbcTemplate jdbcTemplate = new JdbcTemplate(); 099 100 @Nullable 101 private String sqlScriptEncoding; 102 103 104 /** 105 * Set the {@code DataSource}, typically provided via Dependency Injection. 106 * <p>This method also instantiates the {@link #jdbcTemplate} instance variable. 107 */ 108 @Autowired 109 public void setDataSource(DataSource dataSource) { 110 this.jdbcTemplate.setDataSource(dataSource); 111 } 112 113 /** 114 * Specify the encoding for SQL scripts, if different from the platform encoding. 115 * @see #executeSqlScript 116 */ 117 public void setSqlScriptEncoding(String sqlScriptEncoding) { 118 this.sqlScriptEncoding = sqlScriptEncoding; 119 } 120 121 /** 122 * Convenience method for counting the rows in the given table. 123 * @param tableName table name to count rows in 124 * @return the number of rows in the table 125 * @see JdbcTestUtils#countRowsInTable 126 */ 127 protected int countRowsInTable(String tableName) { 128 return JdbcTestUtils.countRowsInTable(this.jdbcTemplate, tableName); 129 } 130 131 /** 132 * Convenience method for counting the rows in the given table, using the 133 * provided {@code WHERE} clause. 134 * <p>See the Javadoc for {@link JdbcTestUtils#countRowsInTableWhere} for details. 135 * @param tableName the name of the table to count rows in 136 * @param whereClause the {@code WHERE} clause to append to the query 137 * @return the number of rows in the table that match the provided 138 * {@code WHERE} clause 139 * @since 3.2 140 * @see JdbcTestUtils#countRowsInTableWhere 141 */ 142 protected int countRowsInTableWhere(String tableName, String whereClause) { 143 return JdbcTestUtils.countRowsInTableWhere(this.jdbcTemplate, tableName, whereClause); 144 } 145 146 /** 147 * Convenience method for deleting all rows from the specified tables. 148 * <p>Use with caution outside of a transaction! 149 * @param names the names of the tables from which to delete 150 * @return the total number of rows deleted from all specified tables 151 * @see JdbcTestUtils#deleteFromTables 152 */ 153 protected int deleteFromTables(String... names) { 154 return JdbcTestUtils.deleteFromTables(this.jdbcTemplate, names); 155 } 156 157 /** 158 * Convenience method for deleting all rows from the given table, using the 159 * provided {@code WHERE} clause. 160 * <p>Use with caution outside of a transaction! 161 * <p>See the Javadoc for {@link JdbcTestUtils#deleteFromTableWhere} for details. 162 * @param tableName the name of the table to delete rows from 163 * @param whereClause the {@code WHERE} clause to append to the query 164 * @param args arguments to bind to the query (leaving it to the {@code 165 * PreparedStatement} to guess the corresponding SQL type); may also contain 166 * {@link org.springframework.jdbc.core.SqlParameterValue SqlParameterValue} 167 * objects which indicate not only the argument value but also the SQL type 168 * and optionally the scale. 169 * @return the number of rows deleted from the table 170 * @since 4.0 171 * @see JdbcTestUtils#deleteFromTableWhere 172 */ 173 protected int deleteFromTableWhere(String tableName, String whereClause, Object... args) { 174 return JdbcTestUtils.deleteFromTableWhere(this.jdbcTemplate, tableName, whereClause, args); 175 } 176 177 /** 178 * Convenience method for dropping all of the specified tables. 179 * <p>Use with caution outside of a transaction! 180 * @param names the names of the tables to drop 181 * @since 3.2 182 * @see JdbcTestUtils#dropTables 183 */ 184 protected void dropTables(String... names) { 185 JdbcTestUtils.dropTables(this.jdbcTemplate, names); 186 } 187 188 /** 189 * Execute the given SQL script. 190 * <p>Use with caution outside of a transaction! 191 * <p>The script will normally be loaded by classpath. 192 * <p><b>Do not use this method to execute DDL if you expect rollback.</b> 193 * @param sqlResourcePath the Spring resource path for the SQL script 194 * @param continueOnError whether or not to continue without throwing an 195 * exception in the event of an error 196 * @throws DataAccessException if there is an error executing a statement 197 * @see ResourceDatabasePopulator 198 * @see #setSqlScriptEncoding 199 */ 200 protected void executeSqlScript(String sqlResourcePath, boolean continueOnError) throws DataAccessException { 201 DataSource ds = this.jdbcTemplate.getDataSource(); 202 Assert.state(ds != null, "No DataSource set"); 203 Assert.state(this.applicationContext != null, "No ApplicationContext available"); 204 Resource resource = this.applicationContext.getResource(sqlResourcePath); 205 new ResourceDatabasePopulator(continueOnError, false, this.sqlScriptEncoding, resource).execute(ds); 206 } 207 208}