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

org.dbunit.assertion.DbUnitAssert 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.assertion;

import java.sql.SQLException;
import java.util.Arrays;

import org.dbunit.Assertion;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.Column;
import org.dbunit.dataset.Columns;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.ITableMetaData;
import org.dbunit.dataset.datatype.DataType;
import org.dbunit.dataset.datatype.UnknownDataType;
import org.dbunit.dataset.filter.DefaultColumnFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Default implementation of DbUnit assertions, based on the original methods present
 * at {@link Assertion}
 * 
 * @author Felipe Leme ([email protected])
 * @author gommma (gommma AT users.sourceforge.net)
 * @version $Revision$ $Date$
 * @since 2.4.0
 */
public class DbUnitAssert
{

    /**
     * Logger for this class
     */
    private static final Logger logger = LoggerFactory.getLogger(DbUnitAssert.class);

    private FailureFactory junitFailureFactory = getJUnitFailureFactory();

    /**
     * Default constructor
     */
    public DbUnitAssert()
    {
    }

    /**
     * Compare one table present in two datasets ignoring specified columns.
     * 
     * @param expectedDataset
     *            First dataset.
     * @param actualDataset
     *            Second dataset.
     * @param tableName
     *            Table name of the table to be compared.
     * @param ignoreCols
     *            Columns to be ignored in comparison.
     * @throws org.dbunit.DatabaseUnitException
     *             If an error occurs.
     */
    public void assertEqualsIgnoreCols(final IDataSet expectedDataset,
            final IDataSet actualDataset, final String tableName,
            final String[] ignoreCols) throws DatabaseUnitException 
    {
        if (logger.isDebugEnabled())
            logger.debug(
                            "assertEqualsIgnoreCols(expectedDataset={}, actualDataset={}, tableName={}, ignoreCols={}) - start",
                    new Object[] { expectedDataset, actualDataset, tableName,
                            Arrays.asList(ignoreCols) });

        assertEqualsIgnoreCols(expectedDataset.getTable(tableName), actualDataset
                .getTable(tableName), ignoreCols);
    }

    /**
     * Compare the given tables ignoring specified columns.
     * 
     * @param expectedTable
     *            First table.
     * @param actualTable
     *            Second table.
     * @param ignoreCols
     *            Columns to be ignored in comparison.
     * @throws org.dbunit.DatabaseUnitException
     *             If an error occurs.
     */
    public void assertEqualsIgnoreCols(final ITable expectedTable,
            final ITable actualTable, final String[] ignoreCols)
    throws DatabaseUnitException 
    {
        if (logger.isDebugEnabled())
            logger
                    .debug(
                            "assertEqualsIgnoreCols(expectedTable={}, actualTable={}, ignoreCols={}) - start",
                            new Object[] {expectedTable, actualTable,
                                    Arrays.asList(ignoreCols)});

        final ITable expectedTableFiltered = DefaultColumnFilter
                .excludedColumnsTable(expectedTable, ignoreCols);
        final ITable actualTableFiltered = DefaultColumnFilter
                .excludedColumnsTable(actualTable, ignoreCols);
        assertEquals(expectedTableFiltered, actualTableFiltered);
    }

    /**
     * Compare a table from a dataset with a table generated from an sql query.
     * 
     * @param expectedDataset
     *            Dataset to retrieve the first table from.
     * @param connection
     *            Connection to use for the SQL statement.
     * @param sqlQuery
     *          SQL query that will build the data in returned second table rows.
     * @param tableName
     *            Table name of the table to compare
     * @param ignoreCols
     *            Columns to be ignored in comparison.
     * @throws DatabaseUnitException
     *             If an error occurs while performing the comparison.
     * @throws java.sql.SQLException
     *             If an SQL error occurs.
     */
    public void assertEqualsByQuery(final IDataSet expectedDataset,
            final IDatabaseConnection connection, final String sqlQuery,
            final String tableName, final String[] ignoreCols)
    throws DatabaseUnitException, SQLException 
    {
        if (logger.isDebugEnabled())
            logger.debug(
                    "assertEqualsByQuery(expectedDataset={}, connection={}, tableName={}, sqlQuery={}, ignoreCols={}) - start",
                    new Object[] { expectedDataset, connection, tableName, sqlQuery,
                            ignoreCols });

        ITable expectedTable = expectedDataset.getTable(tableName);
        assertEqualsByQuery(expectedTable, connection, tableName, sqlQuery,
                ignoreCols);
    }

    /**
     * Compare a table with a table generated from an sql query.
     * 
     * @param expectedTable
     *            Table containing all expected results.
     * @param connection
     *            Connection to use for the SQL statement.
     * @param tableName
     *            The name of the table to query from the database
     * @param sqlQuery
     *          SQL query that will build the data in returned second table rows.
     * @param ignoreCols
     *            Columns to be ignored in comparison.
     * @throws DatabaseUnitException
     *             If an error occurs while performing the comparison.
     * @throws java.sql.SQLException
     *             If an SQL error occurs.
     */
    public void assertEqualsByQuery(final ITable expectedTable,
            final IDatabaseConnection connection, final String tableName,
            final String sqlQuery, final String[] ignoreCols)
    throws DatabaseUnitException, SQLException 
    {
        if (logger.isDebugEnabled())
            logger.debug(
                    "assertEqualsByQuery(expectedTable={}, connection={}, tableName={}, sqlQuery={}, ignoreCols={}) - start",
                    new Object[] { expectedTable, connection, tableName, sqlQuery,
                            ignoreCols });

        ITable expected = DefaultColumnFilter.excludedColumnsTable(expectedTable,
                        ignoreCols);
        ITable queriedTable = connection.createQueryTable(tableName, sqlQuery);
        ITable actual = DefaultColumnFilter.excludedColumnsTable(queriedTable,
                        ignoreCols);
        assertEquals(expected, actual);
    }

    /**
     * Asserts that the two specified dataset are equals. This method ignore the
     * tables order.
     */
    public void assertEquals(IDataSet expectedDataSet, IDataSet actualDataSet)
    throws DatabaseUnitException 
    {
        logger.debug("assertEquals(expectedDataSet={}, actualDataSet={}) - start",
                expectedDataSet, actualDataSet);
        assertEquals(expectedDataSet, actualDataSet, null);
    }

    /**
     * Asserts that the two specified dataset are equals. This method ignore the
     * tables order.
     * 
     * @since 2.4
     */
    public void assertEquals(IDataSet expectedDataSet, IDataSet actualDataSet,
            FailureHandler failureHandler) throws DatabaseUnitException 
    {
        if (logger.isDebugEnabled())
            logger.debug(
                    "assertEquals(expectedDataSet={}, actualDataSet={}, failureHandler={}) - start",
                    new Object[] { expectedDataSet, actualDataSet, failureHandler });

        // do not continue if same instance
        if (expectedDataSet == actualDataSet) {
            return;
        }

        if (failureHandler == null) {
            logger.debug("FailureHandler is null. Using default implementation");
            failureHandler = getDefaultFailureHandler();
        }

        String[] expectedNames = getSortedTableNames(expectedDataSet);
        String[] actualNames = getSortedTableNames(actualDataSet);

        // tables count
        if (expectedNames.length != actualNames.length) {
            throw failureHandler.createFailure("table count", String
                    .valueOf(expectedNames.length), String.valueOf(actualNames.length));
        }

        // table names in no specific order
        for (int i = 0; i < expectedNames.length; i++) {
            if (!actualNames[i].equals(expectedNames[i])) {
                throw failureHandler.createFailure("tables", Arrays.asList(
                        expectedNames).toString(), Arrays.asList(actualNames).toString());
            }

        }

        // tables
        for (int i = 0; i < expectedNames.length; i++) {
            String name = expectedNames[i];
            assertEquals(expectedDataSet.getTable(name), actualDataSet.getTable(name), failureHandler);
        }

    }

    /**
     * Asserts that the two specified tables are equals. This method ignores the
     * table names, the columns order, the columns data type and which columns are
     * composing the primary keys.
     * 
     * @param expectedTable
     *            Table containing all expected results.
     * @param actualTable
     *            Table containing all actual results.
     * @throws DatabaseUnitException
     */
    public void assertEquals(ITable expectedTable, ITable actualTable)
    throws DatabaseUnitException 
    {
        logger.debug("assertEquals(expectedTable={}, actualTable={}) - start",
                expectedTable, actualTable);
        assertEquals(expectedTable, actualTable, (Column[]) null);
    }

    /**
     * Asserts that the two specified tables are equals. This method ignores the
     * table names, the columns order, the columns data type and which columns are
     * composing the primary keys. 
* Example:
     * ITable actualTable = ...;
     * ITable expectedTable = ...;
     * ITableMetaData metaData = actualTable.getTableMetaData();
     * Column[] additionalInfoCols = Columns.getColumns(new String[] {"MY_PK_COLUMN"}, metaData.getColumns());
     * assertEquals(expectedTable, actualTable, additionalInfoCols);
     * 
* * @param expectedTable * Table containing all expected results. * @param actualTable * Table containing all actual results. * @param additionalColumnInfo * The columns to be printed out if the assert fails because of a * data mismatch. Provides some additional column values that may be * useful to quickly identify the columns for which the mismatch * occurred (for example a primary key column). Can be * null * @throws DatabaseUnitException */ public void assertEquals(ITable expectedTable, ITable actualTable, Column[] additionalColumnInfo) throws DatabaseUnitException { logger.debug( "assertEquals(expectedTable={}, actualTable={}, additionalColumnInfo={}) - start", new Object[] { expectedTable, actualTable, additionalColumnInfo }); FailureHandler failureHandler = null; if (additionalColumnInfo != null) failureHandler = getDefaultFailureHandler(additionalColumnInfo); assertEquals(expectedTable, actualTable, failureHandler); } /** * Asserts that the two specified tables are equals. This method ignores the * table names, the columns order, the columns data type and which columns are * composing the primary keys.
* Example:
     * ITable actualTable = ...;
     * ITable expectedTable = ...;
     * ITableMetaData metaData = actualTable.getTableMetaData();
     * FailureHandler failureHandler = new DefaultFailureHandler();
     * assertEquals(expectedTable, actualTable, failureHandler);
     * 
* * @param expectedTable * Table containing all expected results. * @param actualTable * Table containing all actual results. * @param failureHandler * The failure handler used if the assert fails because of a data * mismatch. Provides some additional information that may be useful * to quickly identify the rows for which the mismatch occurred (for * example by printing an additional primary key column). Can be * null * @throws DatabaseUnitException * @since 2.4 */ public void assertEquals(ITable expectedTable, ITable actualTable, FailureHandler failureHandler) throws DatabaseUnitException { logger.trace("assertEquals(expectedTable, actualTable, failureHandler) - start"); logger.debug("assertEquals: expectedTable={}", expectedTable); logger.debug("assertEquals: actualTable={}", actualTable); logger.debug("assertEquals: failureHandler={}", failureHandler); // Do not continue if same instance if (expectedTable == actualTable) { logger.debug( "The given tables reference the same object. Will return immediately. (Table={})", expectedTable); return; } if (failureHandler == null) { logger.debug("FailureHandler is null. Using default implementation"); failureHandler = getDefaultFailureHandler(); } ITableMetaData expectedMetaData = expectedTable.getTableMetaData(); ITableMetaData actualMetaData = actualTable.getTableMetaData(); String expectedTableName = expectedMetaData.getTableName(); // Verify row count int expectedRowsCount = expectedTable.getRowCount(); int actualRowsCount = 0; boolean skipRowComparison = false; try { actualRowsCount = actualTable.getRowCount(); } catch(UnsupportedOperationException exception) { skipRowComparison = true; } if(!skipRowComparison) { if (expectedRowsCount != actualRowsCount) { String msg = "row count (table=" + expectedTableName + ")"; Error error = failureHandler.createFailure(msg, String .valueOf(expectedRowsCount), String .valueOf(actualRowsCount)); logger.error(error.toString()); throw error; } // if both tables are empty, it is not necessary to compare columns, as // such comparison can fail if column metadata is different (which // could occurs when comparing empty tables) if (expectedRowsCount == 0 && actualRowsCount == 0) { logger.debug("Tables are empty, hence equals."); return; } } // Put the columns into the same order Column[] expectedColumns = Columns.getSortedColumns(expectedMetaData); Column[] actualColumns = Columns.getSortedColumns(actualMetaData); // Verify columns Columns.ColumnDiff columnDiff = Columns.getColumnDiff(expectedMetaData, actualMetaData); if (columnDiff.hasDifference()) { String message = columnDiff.getMessage(); Error error = failureHandler.createFailure(message, Columns .getColumnNamesAsString(expectedColumns), Columns .getColumnNamesAsString(actualColumns)); logger.error(error.toString()); throw error; } // Get the datatypes to be used for comparing the sorted columns ComparisonColumn[] comparisonCols = getComparisonColumns(expectedTableName, expectedColumns, actualColumns, failureHandler); // Finally compare the data compareData(expectedTable, actualTable, comparisonCols, failureHandler); } /** * @return The default failure handler * @since 2.4 */ protected FailureHandler getDefaultFailureHandler() { return getDefaultFailureHandler(null); } /** * @return The default failure handler * @since 2.4 */ protected FailureHandler getDefaultFailureHandler(Column[] additionalColumnInfo) { DefaultFailureHandler failureHandler = new DefaultFailureHandler(additionalColumnInfo); if (junitFailureFactory != null) { failureHandler.setFailureFactory(junitFailureFactory); } return failureHandler; } /** * @return the JUnitFailureFactory if JUnit is on the classpath or null if * JUnit is not on the classpath. */ private FailureFactory getJUnitFailureFactory() { try { Class.forName("junit.framework.Assert"); // JUnit available return new JUnitFailureFactory(); } catch (ClassNotFoundException e) { // JUnit not available on the classpath return null logger.debug("JUnit does not seem to be on the classpath. " + e); } return null; } /** * @param expectedTable * Table containing all expected results. * @param actualTable * Table containing all actual results. * @param comparisonCols * The columns to be compared, also including the correct * {@link DataType}s for comparison * @param failureHandler * The failure handler used if the assert fails because of a data * mismatch. Provides some additional information that may be useful * to quickly identify the rows for which the mismatch occurred (for * example by printing an additional primary key column). Must not be * null at this stage * @throws DataSetException * @since 2.4 */ protected void compareData(ITable expectedTable, ITable actualTable, ComparisonColumn[] comparisonCols, FailureHandler failureHandler) throws DataSetException { logger.debug("compareData(expectedTable={}, actualTable={}, " + "comparisonCols={}, failureHandler={}) - start", new Object[] {expectedTable, actualTable, comparisonCols, failureHandler}); if (expectedTable == null) { throw new NullPointerException( "The parameter 'expectedTable' must not be null"); } if (actualTable == null) { throw new NullPointerException( "The parameter 'actualTable' must not be null"); } if (comparisonCols == null) { throw new NullPointerException( "The parameter 'comparisonCols' must not be null"); } if (failureHandler == null) { throw new NullPointerException( "The parameter 'failureHandler' must not be null"); } // iterate over all rows for (int i = 0; i < expectedTable.getRowCount(); i++) { // iterate over all columns of the current row for (int j = 0; j < comparisonCols.length; j++) { ComparisonColumn compareColumn = comparisonCols[j]; String columnName = compareColumn.getColumnName(); DataType dataType = compareColumn.getDataType(); Object expectedValue = expectedTable.getValue(i, columnName); Object actualValue = actualTable.getValue(i, columnName); // Compare the values if (skipCompare(columnName, expectedValue, actualValue)) { if (logger.isTraceEnabled()) { logger.trace( "ignoring comparison " + expectedValue + "=" + actualValue + " on column " + columnName); } continue; } if (dataType.compare(expectedValue, actualValue) != 0) { Difference diff = new Difference( expectedTable, actualTable, i, columnName, expectedValue, actualValue); // Handle the difference (throw error immediately or something else) failureHandler.handle(diff); } } } } /** * Method to last-minute intercept the comparison of a single * expected and actual value. Designed to be overridden in order * to skip cell comparison by specific cell values. * * @param columnName The column being compared * @param expectedValue The expected value to be compared * @param actualValue The actual value to be compared * @return false always so that the comparison is never skipped * @since 2.4 */ protected boolean skipCompare(String columnName, Object expectedValue, Object actualValue) { return false; } /** * @param expectedTableName * @param expectedColumns * @param actualColumns * @param failureHandler * The {@link FailureHandler} to be used when no datatype can be * determined * @return The columns to be used for the assertion, including the correct * datatype * @since 2.4 */ protected ComparisonColumn[] getComparisonColumns(String expectedTableName, Column[] expectedColumns, Column[] actualColumns, FailureHandler failureHandler) { ComparisonColumn[] result = new ComparisonColumn[expectedColumns.length]; for (int j = 0; j < expectedColumns.length; j++) { Column expectedColumn = expectedColumns[j]; Column actualColumn = actualColumns[j]; result[j] = new ComparisonColumn(expectedTableName, expectedColumn, actualColumn, failureHandler); } return result; } protected String[] getSortedTableNames(IDataSet dataSet) throws DataSetException { logger.debug("getSortedTableNames(dataSet={}) - start", dataSet); String[] names = dataSet.getTableNames(); if( !dataSet.isCaseSensitiveTableNames() ) { for (int i = 0; i < names.length; i++) { names[i] = names[i].toUpperCase(); } } Arrays.sort(names); return names; } /** * Represents a single column to be used for the comparison of table data. It * contains the {@link DataType} to be used for comparing the given column. * This {@link DataType} matches the expected and actual column's datatype. * * @author gommma (gommma AT users.sourceforge.net) * @author Last changed by: $Author: gommma $ * @version $Revision: 864 $ $Date: 2008-11-07 06:27:26 -0800 (Fri, 07 Nov * 2008) $ * @since 2.4.0 */ public static class ComparisonColumn { /** * Logger for this class */ private static final Logger logger = LoggerFactory .getLogger(ComparisonColumn.class); private String columnName; private DataType dataType; /** * @param tableName * The table name which is only needed for debugging output * @param expectedColumn * The expected column needed to resolve the {@link DataType} to * use for the actual comparison * @param actualColumn * The actual column needed to resolve the {@link DataType} to use * for the actual comparison * @param failureHandler * The {@link FailureHandler} to be used when no datatype can be * determined */ public ComparisonColumn(String tableName, Column expectedColumn, Column actualColumn, FailureHandler failureHandler) { super(); this.columnName = expectedColumn.getColumnName(); this.dataType = getComparisonDataType(tableName, expectedColumn, actualColumn, failureHandler); } /** * @return The column actually being compared */ public String getColumnName() { return this.columnName; } /** * @return The {@link DataType} to use for the actual comparison */ public DataType getDataType() { return this.dataType; } /** * @param tableName * The table name which is only needed for debugging output * @param expectedColumn * @param actualColumn * @param failureHandler * The {@link FailureHandler} to be used when no datatype can be * determined * @return The dbunit {@link DataType} to use for comparing the given * column. */ private DataType getComparisonDataType(String tableName, Column expectedColumn, Column actualColumn, FailureHandler failureHandler) { if (logger.isDebugEnabled()) logger.debug( "getComparisonDataType(tableName={}, expectedColumn={}, actualColumn={}, failureHandler={}) - start", new Object[] { tableName, expectedColumn, actualColumn, failureHandler }); DataType expectedDataType = expectedColumn.getDataType(); DataType actualDataType = actualColumn.getDataType(); // The two columns have different data type if (!expectedDataType.getClass().isInstance(actualDataType)) { // Expected column data type is unknown, use actual column data type if (expectedDataType instanceof UnknownDataType) { return actualDataType; } // Actual column data type is unknown, use expected column data type if (actualDataType instanceof UnknownDataType) { return expectedDataType; } // Impossible to determine which data type to use String msg = "Incompatible data types: (table=" + tableName + ", col=" + expectedColumn.getColumnName() + ")"; throw failureHandler.createFailure(msg, String .valueOf(expectedDataType), String.valueOf(actualDataType)); } // Both columns have same data type, return any one of them return expectedDataType; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy