org.dbunit.DefaultPrepAndExpectedTestCase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xmlc-chtml Show documentation
Show all versions of xmlc-chtml Show documentation
old 2002 version of xmlc-xmlc-chtml
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:
*
* - Dependency inject it as its interface into a test class.
*
* Configure a bean of its interface, injecting a IDatabaseTester and a
* DataFileLoader using the databaseTester and a dataFileLoader properties.
*
*
* - Extend it in a test class.
*
* 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
*
* - For additional examples, refer to the ITs (listed in the See Also
* section).
* - 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.
* - To set DatabaseConfig features/properties, one way is to extend this
* class and override the setUpDatabaseConfig(DatabaseConfig config) method from
* DatabaseTestCase.
*
*
* @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;
}
}