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