All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dbunit.DefaultPrepAndExpectedTestCase Maven / Gradle / Ivy

The newest version!
/*
 *
 * The DbUnit Database Testing Framework
 * Copyright (C)2002-2008, DbUnit.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
package org.dbunit;

import java.util.ArrayList;
import java.util.List;

import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.Column;
import org.dbunit.dataset.CompositeDataSet;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.DefaultDataSet;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.SortedTable;
import org.dbunit.dataset.filter.DefaultColumnFilter;
import org.dbunit.operation.DatabaseOperation;
import org.dbunit.util.fileloader.DataFileLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Test case base class supporting prep data and expected data. Prep data is the
 * data needed for the test to run. Expected data is the data needed to compare
 * if the test ran successfully.
 *
 * Use this class in two ways:
 * 
    *
  1. Dependency inject it as its interface into a test class.
  2. *

    * Configure a bean of its interface, injecting a IDatabaseTester and a * DataFileLoader using the databaseTester and a dataFileLoader properties. *

    * *
  3. Extend it in a test class.
  4. *

    * Obtain IDatabaseTester and DataFileLoader instances (possibly dependency * injecting them into the test class) and set them accordingly, probably in a * setup type of method, such as: * *

     * @Before
     * public void setDbunitTestDependencies()
     * {
     *     setDatabaseTester(databaseTester);
     *     setDataFileLoader(dataFileLoader);
     * }
     * 
    * *

    *
* * To setup, execute, and clean up tests, call the configureTest(), preTest(), * and postTest() methods. Note there is a preTest() convenience method that * takes the same parameters as the configureTest() method; use it instead of * using both configureTest() and preTest(). * * Where the test case calls them depends on data needs: *
    *
  • For the whole test case, i.e. in setUp() and tearDown() or @Before * and @After.
  • *
  • In each test method.
  • *
  • Or some combination of both test case setup/teardown and test methods. *
  • *
* *

When each test method requires different prep and expected data

* * If each test method requires its own prep and expected data, then the test * methods will look something like the following: * *
 * @Autowired
 * private PrepAndExpectedTestCase tc;
 *
 * @Test
 * public void testExample() throws Exception
 * {
 *     try
 *     {
 *         final String[] prepDataFiles = {}; // define prep files
 *         final String[] expectedDataFiles = {}; // define expected files
 *         final VerifyTableDefinition[] tables = {}; // define tables to verify
 *
 *         tc.preTest(tables, prepDataFiles, expectedDataFiles);
 *
 *         // execute test steps
 *     } catch (Exception e)
 *     {
 *         log.error("Test error", e);
 *         throw e;
 *     } finally
 *     {
 *         tc.postTest();
 *     }
 * }
 * 
* *

When all test methods share the same prep and/or expected data

* * If each test method can share all of the prep and/or expected data, then use * setUp() for the configureTest() and preTest() calls and tearDown() for the * postTest() call. The methods will look something like the following: * *
 * @Override
 * protected void setUp() throws Exception
 * {
 *     setDatabaseTester(databaseTester);
 *     setDataFileLoader(dataFileLoader);
 *
 *     String[] prepDataFiles = {}; // define prep files
 *     String[] expectedDataFiles = {}; // define expected files
 *     VerifyTableDefinition[] tables = {}; // define tables to verify
 *
 *     preTest(tables, prepDataFiles, expectedDataFiles);
 *
 *     // call this if overriding setUp() and databaseTester & dataFileLoader
 *     // are already set.
 *     super.setUp();
 * }
 *
 * @Override
 * protected void tearDown() throws Exception
 * {
 *     postTest();
 *     super.tearDown();
 * }
 *
 * @Test
 * public void testExample() throws Exception
 * {
 *     // execute test steps
 * }
 * 
* * Note that it is unlikely that all test methods can share the same expected * data. * *

Sharing common (but not all) prep or expected data among test methods. *

* * Put common data in one or more files and pass the needed ones in the correct * data file array. * *

Java 8 and Anonymous Interfaces

*

* Release 2.5.2 introduced interface {@link PrepAndExpectedTestCaseSteps} and * the * {@link #runTest(VerifyTableDefinition[], String[], String[], PrepAndExpectedTestCaseSteps)} * method. This allows for encapsulating test steps into an anonymous inner * class or a Java 8+ lambda and avoiding the try/catch/finally template in * tests. *

* *
 * @Autowired
 * private PrepAndExpectedTestCase tc;
 *
 * @Test
 * public void testExample() throws Exception
 * {
 *     final String[] prepDataFiles = {}; // define prep files
 *     final String[] expectedDataFiles = {}; // define expected files
 *     final VerifyTableDefinition[] tables = {}; // define tables to verify
 *     final PrepAndExpectedTestCaseSteps testSteps = () -> {
 *         // execute test steps
 *
 *         return null; // or an object for use outside the Steps
 *     };
 *
 *     tc.runTest(tables, prepDataFiles, expectedDataFiles, testSteps);
 * }
 * 
* *

Notes

*
    *
  1. For additional examples, refer to the ITs (listed in the See Also * section).
  2. *
  3. To change the setup or teardown operation (e.g. change the teardown to * org.dbunit.operation.DatabaseOperation.DELETE_ALL), set the setUpOperation or * tearDownOperation property on the databaseTester.
  4. *
  5. To set DatabaseConfig features/properties, one way is to extend this * class and override the setUpDatabaseConfig(DatabaseConfig config) method from * DatabaseTestCase.
  6. *
* * @see org.dbunit.DefaultPrepAndExpectedTestCaseDiIT * @see org.dbunit.DefaultPrepAndExpectedTestCaseExtIT * * @author Jeff Jensen jeffjensen AT users.sourceforge.net * @author Last changed by: $Author$ * @version $Revision$ $Date$ * @since 2.4.8 */ public class DefaultPrepAndExpectedTestCase extends DBTestCase implements PrepAndExpectedTestCase { private final Logger log = LoggerFactory.getLogger(DefaultPrepAndExpectedTestCase.class); public static final String TEST_ERROR_MSG = "DbUnit test error."; private IDatabaseTester databaseTester; private DataFileLoader dataFileLoader; private IDataSet prepDs = new DefaultDataSet(); private IDataSet expectedDs = new DefaultDataSet(); private VerifyTableDefinition[] tableDefs = {}; /** Create new instance. */ public DefaultPrepAndExpectedTestCase() { } /** * Create new instance with specified dataFileLoader and databasetester. * * @param dataFileLoader * Load to use for loading the data files. * @param databaseTester * Tester to use for database manipulation. */ public DefaultPrepAndExpectedTestCase(DataFileLoader dataFileLoader, IDatabaseTester databaseTester) { this.dataFileLoader = dataFileLoader; this.databaseTester = databaseTester; } /** * Create new instance with specified test case name. * * @param name * The test case name. */ public DefaultPrepAndExpectedTestCase(String name) { super(name); } /** * {@inheritDoc} This implementation returns the databaseTester set by the * test. */ @Override public IDatabaseTester newDatabaseTester() throws Exception { // questionable, but there is not a "setter" for any parent... return databaseTester; } /** * {@inheritDoc} Returns the prep dataset. */ @Override public IDataSet getDataSet() throws Exception { return prepDs; } /** * {@inheritDoc} */ public void configureTest(VerifyTableDefinition[] tables, String[] prepDataFiles, String[] expectedDataFiles) throws Exception { log.debug("configureTest: saving instance variables"); this.prepDs = makeCompositeDataSet(prepDataFiles); this.expectedDs = makeCompositeDataSet(expectedDataFiles); this.tableDefs = tables; } /** * {@inheritDoc} */ public void preTest() throws Exception { setupData(); } /** * {@inheritDoc} */ public void preTest(VerifyTableDefinition[] tables, String[] prepDataFiles, String[] expectedDataFiles) throws Exception { configureTest(tables, prepDataFiles, expectedDataFiles); preTest(); } /** * {@inheritDoc} */ public Object runTest(VerifyTableDefinition[] verifyTables, String[] prepDataFiles, String[] expectedDataFiles, PrepAndExpectedTestCaseSteps testSteps) throws Exception { final Object result; try { preTest(verifyTables, prepDataFiles, expectedDataFiles); result = testSteps.run(); } catch (final Exception e) { log.error(TEST_ERROR_MSG, e); // don't verify table data when test execution has errors as: // * a verify data failure masks the test error exception // * tables in unknown state and therefore probably not accurate postTest(false); throw e; } postTest(); return result; } /** * {@inheritDoc} */ public void postTest() throws Exception { postTest(true); } /** * {@inheritDoc} */ public void postTest(boolean verifyData) throws Exception { try { if (verifyData) { verifyData(); } } finally { // it is deliberate to have cleanup exceptions shadow verify // failures so user knows db is probably in unknown state (for // those not using an in-memory db or transaction rollback), // otherwise would mask probable cause of subsequent test failures cleanupData(); } } /** * {@inheritDoc} */ public void cleanupData() throws Exception { try { IDataSet dataset = new CompositeDataSet(prepDs, expectedDs); String tableNames[] = dataset.getTableNames(); int count = tableNames.length; log.info("cleanupData: about to clean up {} tables={}", new Integer(count), tableNames); if (databaseTester == null) { throw new IllegalStateException( "databaseTester is null; must configure or set it first"); } databaseTester.setTearDownOperation(getTearDownOperation()); databaseTester.setDataSet(dataset); databaseTester.setOperationListener(getOperationListener()); databaseTester.onTearDown(); log.debug("cleanupData: Clean up done"); } catch (Exception e) { log.error("cleanupData: Exception:", e); throw e; } } @Override protected void tearDown() throws Exception { // parent tearDown() only cleans up prep data cleanupData(); super.tearDown(); } /** * Use the provided databaseTester to prep the database with the provided * prep dataset. See {@link org.dbunit.IDatabaseTester#onSetup()}. * * @throws Exception */ public void setupData() throws Exception { log.debug("setupData: setting prep dataset and inserting rows"); if (databaseTester == null) { throw new IllegalStateException( "databaseTester is null; must configure or set it first"); } try { super.setUp(); } catch (Exception e) { log.error("setupData: Exception with setting up data:", e); throw e; } } @Override protected DatabaseOperation getSetUpOperation() throws Exception { assertNotNull("databaseTester is null; must configure or set it first", databaseTester); return databaseTester.getSetUpOperation(); } @Override protected DatabaseOperation getTearDownOperation() throws Exception { assertNotNull("databaseTester is null; must configure or set it first", databaseTester); return databaseTester.getTearDownOperation(); } /** * {@inheritDoc} Uses the connection from the provided databaseTester. */ public void verifyData() throws Exception { if (databaseTester == null) { throw new IllegalStateException( "databaseTester is null; must configure or set it first"); } IDatabaseConnection connection = getConnection(); try { int count = tableDefs.length; log.info("verifyData: about to verify {} tables={}", new Integer(count), tableDefs); if (count == 0) { log.warn("verifyData: No tables to verify;" + " no VerifyTableDefinitions specified"); } for (int i = 0; i < count; i++) { VerifyTableDefinition td = tableDefs[i]; String[] excludeColumns = td.getColumnExclusionFilters(); String[] includeColumns = td.getColumnInclusionFilters(); String tableName = td.getTableName(); log.info("verifyData: Verifying table '{}'", tableName); log.debug("verifyData: Loading its rows from expected dataset"); ITable expectedTable = null; try { expectedTable = expectedDs.getTable(tableName); } catch (Exception e) { final String msg = "verifyData: Problem obtaining table '" + tableName + "' from expected dataset"; log.error(msg, e); throw new DataSetException(msg, e); } log.debug("verifyData: Loading its rows from actual table"); ITable actualTable = null; try { actualTable = connection.createTable(tableName); } catch (Exception e) { final String msg = "verifyData: Problem obtaining table '" + tableName + "' from actual dataset"; log.error(msg, e); throw new DataSetException(msg, e); } verifyData(expectedTable, actualTable, excludeColumns, includeColumns); } } catch (Exception e) { log.error("verifyData: Exception:", e); throw e; } finally { log.debug("verifyData: Verification done, closing connection"); connection.close(); } } /** * For the specified expected and actual tables (and excluding and including * the specified columns), verify the actual data is as expected. * * @param expectedTable * The expected table to compare the actual table to. * @param actualTable * The actual table to compare to the expected table. * @param excludeColumns * The column names to exclude from comparison. See * {@link org.dbunit.dataset.filter.DefaultColumnFilter#excludeColumn(String)} * . * @param includeColumns * The column names to only include in comparison. See * {@link org.dbunit.dataset.filter.DefaultColumnFilter#includeColumn(String)} * . * @throws DatabaseUnitException */ public void verifyData(ITable expectedTable, ITable actualTable, String[] excludeColumns, String[] includeColumns) throws DatabaseUnitException { final String method = "verifyData: "; // Filter out the columns from the expected and actual results log.debug(method + "Applying filters to expected table"); ITable expectedFilteredTable = applyColumnFilters(expectedTable, excludeColumns, includeColumns); log.debug(method + "Applying filters to actual table"); ITable actualFilteredTable = applyColumnFilters(actualTable, excludeColumns, includeColumns); log.debug(method + "Sorting expected table"); SortedTable expectedSortedTable = new SortedTable(expectedFilteredTable); log.debug(method + "Sorted expected table={}", expectedSortedTable); log.debug(method + "Sorting actual table"); SortedTable actualSortedTable = new SortedTable(actualFilteredTable, expectedFilteredTable.getTableMetaData()); log.debug(method + "Sorted actual table={}", actualSortedTable); log.debug(method + "Comparing expected table to actual table"); Column[] additionalColumnInfo = expectedTable.getTableMetaData().getColumns(); Assertion.assertEquals(expectedSortedTable, actualSortedTable, additionalColumnInfo); } /** * Make a IDataSet from the specified files. * * @param dataFiles * Represents the array of dbUnit data files. * @return The composite dataset. * @throws DataSetException * On dbUnit errors. */ public IDataSet makeCompositeDataSet(String[] dataFiles) throws DataSetException { if (dataFileLoader == null) { throw new IllegalStateException( "dataFileLoader is null; must configure or set it first"); } int count = dataFiles.length; log.debug("makeCompositeDataSet: dataFiles count=" + count); if (count == 0) { log.info("makeCompositeDataSet: Specified zero data files"); } List list = new ArrayList(); for (int i = 0; i < count; i++) { IDataSet ds = dataFileLoader.load(dataFiles[i]); list.add(ds); } IDataSet[] dataSet = (IDataSet[]) list.toArray(new IDataSet[] {}); IDataSet compositeDS = new CompositeDataSet(dataSet); return compositeDS; } /** * Apply the specified exclude and include column filters to the specified * table. * * @param table * The table to apply the filters to. * @param excludeColumns * The exclude filters; use null or empty array to mean exclude * none. * @param includeColumns * The include filters; use null to mean include all. * @return The filtered table. * @throws DataSetException */ public ITable applyColumnFilters(ITable table, String[] excludeColumns, String[] includeColumns) throws DataSetException { ITable filteredTable = table; if (table == null) { throw new IllegalArgumentException("table is null"); } // note: dbunit interprets an empty inclusion filter array as one // not wanting to compare anything! if (includeColumns == null) { log.debug("applyColumnFilters: including columns=(all)"); } else { log.debug("applyColumnFilters: including columns='{}'", new Object[] {includeColumns}); filteredTable = DefaultColumnFilter .includedColumnsTable(filteredTable, includeColumns); } if (excludeColumns == null || excludeColumns.length == 0) { log.debug("applyColumnFilters: excluding columns=(none)"); } else { log.debug("applyColumnFilters: excluding columns='{}'", new Object[] {excludeColumns}); filteredTable = DefaultColumnFilter .excludedColumnsTable(filteredTable, excludeColumns); } return filteredTable; } /** * {@inheritDoc} */ public IDataSet getPrepDataset() { return prepDs; } /** * {@inheritDoc} */ public IDataSet getExpectedDataset() { return expectedDs; } /** * Get the databaseTester. * * @see {@link databaseTester}. * * @return The databaseTester. */ @Override public IDatabaseTester getDatabaseTester() { return databaseTester; } /** * Set the databaseTester. * * @see {@link databaseTester}. * * @param databaseTester * The databaseTester to set. */ public void setDatabaseTester(IDatabaseTester databaseTester) { this.databaseTester = databaseTester; } /** * Get the dataFileLoader. * * @see {@link dataFileLoader}. * * @return The dataFileLoader. */ public DataFileLoader getDataFileLoader() { return dataFileLoader; } /** * Set the dataFileLoader. * * @see {@link dataFileLoader}. * * @param dataFileLoader * The dataFileLoader to set. */ public void setDataFileLoader(DataFileLoader dataFileLoader) { this.dataFileLoader = dataFileLoader; } /** * Set the prepDs. * * @see {@link prepDs}. * * @param prepDs * The prepDs to set. */ public void setPrepDs(IDataSet prepDs) { this.prepDs = prepDs; } /** * Set the expectedDs. * * @see {@link expectedDs}. * * @param expectedDs * The expectedDs to set. */ public void setExpectedDs(IDataSet expectedDs) { this.expectedDs = expectedDs; } /** * Get the tableDefs. * * @see {@link tableDefs}. * * @return The tableDefs. */ public VerifyTableDefinition[] getTableDefs() { return tableDefs; } /** * Set the tableDefs. * * @see {@link tableDefs}. * * @param tableDefs * The tableDefs to set. */ public void setTableDefs(VerifyTableDefinition[] tableDefs) { this.tableDefs = tableDefs; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy