com.yeahmobi.yunit.DbUnitRunner.java Source code

Java tutorial

Introduction

Here is the source code for com.yeahmobi.yunit.DbUnitRunner.java

Source

/*
 * Copyright 2002-2013 the original author or authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.yeahmobi.yunit;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.yeahmobi.yunit.annotation.DatabaseOperation;
import com.yeahmobi.yunit.annotation.DatabaseSetup;
import com.yeahmobi.yunit.annotation.DatabaseTearDown;
import com.yeahmobi.yunit.annotation.ExpectedDatabase;
import com.yeahmobi.yunit.assertion.DatabaseAssertion;
import com.yeahmobi.yunit.dataset.DataSetLoader;

/**
 * Internal delegate class used to run tests with support for {@link DatabaseSetup @DatabaseSetup},
 * {@link DatabaseTearDown @DatabaseTearDown} and {@link ExpectedDatabase @ExpectedDatabase} annotations.
 *
 * @author Phillip Webb
 * @author Mario Zagar
 * @author Sunitha Rajarathnam
 */
class DbUnitRunner {

    private static final Log logger = LogFactory.getLog(DbUnitTestExecutionListener.class);

    /**
     * Called before a test method is executed to perform any database setup.
     * @param testContext The test context
     * @throws Exception
     */
    public void beforeTestMethod(DbUnitTestContext testContext) throws Exception {
        Collection<DatabaseSetup> annotations = getAnnotations(testContext, DatabaseSetup.class);
        setupOrTeardown(testContext, true, AnnotationAttributes.get(annotations));
    }

    /**
     * Called after a test method is executed to perform any database teardown and to check expected results.
     * @param testContext The test context
     * @throws Exception
     */
    public void afterTestMethod(DbUnitTestContext testContext) throws Exception {
        try {
            verifyExpected(testContext, getAnnotations(testContext, ExpectedDatabase.class));
            Collection<DatabaseTearDown> annotations = getAnnotations(testContext, DatabaseTearDown.class);
            try {
                setupOrTeardown(testContext, false, AnnotationAttributes.get(annotations));
            } catch (RuntimeException e) {
                if (testContext.getTestException() == null) {
                    throw e;
                }
                if (logger.isWarnEnabled()) {
                    logger.warn("Unable to throw database cleanup exception due to existing test error", e);
                }
            }
        } finally {
            testContext.getConnection().close();
        }
    }

    private <T extends Annotation> Collection<T> getAnnotations(DbUnitTestContext testContext,
            Class<T> annotationType) {
        List<T> annotations = new ArrayList<T>();
        addAnnotationToList(annotations,
                AnnotationUtils.findAnnotation(testContext.getTestClass(), annotationType));
        addAnnotationToList(annotations,
                AnnotationUtils.findAnnotation(testContext.getTestMethod(), annotationType));
        return annotations;
    }

    private <T extends Annotation> void addAnnotationToList(List<T> annotations, T annotation) {
        if (annotation != null) {
            annotations.add(annotation);
        }
    }

    private void verifyExpected(DbUnitTestContext testContext, Collection<ExpectedDatabase> annotations)
            throws Exception {
        if (testContext.getTestException() != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Skipping @DatabaseTest expectation due to test exception "
                        + testContext.getTestException().getClass());
            }
            return;
        }
        IDatabaseConnection connection = testContext.getConnection();
        for (ExpectedDatabase annotation : annotations) {
            String query = annotation.query();
            String table = annotation.table();
            IDataSet expectedDataSet = loadDataset(testContext, annotation.value(), "expected.xml");
            if (expectedDataSet != null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Veriftying @DatabaseTest expectation using " + annotation.value());
                }
                DatabaseAssertion assertion = annotation.assertionMode().getDatabaseAssertion();
                if (StringUtils.hasLength(query)) {
                    Assert.hasLength(table, "The table name must be specified when using a SQL query");
                    ITable expectedTable = expectedDataSet.getTable(table);
                    ITable actualTable = connection.createQueryTable(table, query);
                    assertion.assertEquals(expectedTable, actualTable);
                } else if (StringUtils.hasLength(table)) {
                    ITable actualTable = connection.createTable(table);
                    ITable expectedTable = expectedDataSet.getTable(table);
                    assertion.assertEquals(expectedTable, actualTable);
                } else {
                    IDataSet actualDataSet = connection.createDataSet();
                    assertion.assertEquals(expectedDataSet, actualDataSet);
                }
            }
        }
    }

    private IDataSet loadDataset(DbUnitTestContext testContext, String dataSetLocation, String suffix)
            throws Exception {
        DataSetLoader dataSetLoader = testContext.getDataSetLoader();
        IDataSet dataSet = dataSetLoader.loadDataSet(testContext.getTestClass(), testContext.getTestMethod(),
                dataSetLocation, suffix);
        Assert.notNull(dataSet,
                "Unable to load dataset from \"" + getLocations(testContext.getTestClass(),
                        testContext.getTestMethod(), dataSetLocation, suffix) + "\" using "
                        + dataSetLoader.getClass());
        return dataSet;
    }

    private List<String> getLocations(Class<?> testClass, Method testMethod, String location, String suffix) {
        List<String> list = new ArrayList<String>();
        if ((location != null) && !"".equals(location)) {
            list.add(location);
        } else {
            list.add(testClass.getSimpleName() + "-" + testMethod.getName() + "-" + suffix);
            list.add(testClass.getSimpleName() + "-" + suffix);
            list.add(suffix);
        }
        return list;
    }

    private void setupOrTeardown(DbUnitTestContext testContext, boolean isSetup,
            Collection<AnnotationAttributes> annotations) throws Exception {
        IDatabaseConnection connection = testContext.getConnection();
        DatabaseOperation lastOperation = null;
        for (AnnotationAttributes annotation : annotations) {
            for (String dataSetLocation : annotation.getValue()) {
                DatabaseOperation operation = annotation.getType();
                org.dbunit.operation.DatabaseOperation dbUnitDatabaseOperation = getDbUnitDatabaseOperation(
                        testContext, operation, lastOperation);
                String suffix = isSetup ? "setup.xml" : "teardown.xml";
                IDataSet dataSet = loadDataset(testContext, dataSetLocation, suffix);
                if (dataSet != null) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Executing " + (isSetup ? "Setup" : "Teardown") + " of @DatabaseTest using "
                                + operation + " on " + getLocations(testContext.getTestClass(),
                                        testContext.getTestMethod(), dataSetLocation, suffix));
                    }
                    dbUnitDatabaseOperation.execute(connection, dataSet);
                    lastOperation = operation;
                }
            }
        }
    }

    private org.dbunit.operation.DatabaseOperation getDbUnitDatabaseOperation(DbUnitTestContext testContext,
            DatabaseOperation operation, DatabaseOperation lastOperation) {
        if ((operation == DatabaseOperation.CLEAN_INSERT) && (lastOperation == DatabaseOperation.CLEAN_INSERT)) {
            operation = DatabaseOperation.INSERT;
        }
        org.dbunit.operation.DatabaseOperation databaseOperation = testContext.getDatbaseOperationLookup()
                .get(operation);
        Assert.state(databaseOperation != null, "The databse operation " + operation + " is not supported");
        return databaseOperation;
    }

    private static class AnnotationAttributes {

        private DatabaseOperation type;

        private String[] value;

        public AnnotationAttributes(Annotation annotation) {
            Assert.state((annotation instanceof DatabaseSetup) || (annotation instanceof DatabaseTearDown),
                    "Only DatabaseSetup and DatabaseTearDown annotations are supported");
            Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
            this.type = (DatabaseOperation) attributes.get("type");
            this.value = (String[]) attributes.get("value");
        }

        public DatabaseOperation getType() {
            return this.type;
        }

        public String[] getValue() {
            return this.value;
        }

        public static <T extends Annotation> Collection<AnnotationAttributes> get(Collection<T> annotations) {
            List<AnnotationAttributes> annotationAttributes = new ArrayList<AnnotationAttributes>();
            for (T annotation : annotations) {
                annotationAttributes.add(new AnnotationAttributes(annotation));
            }
            return annotationAttributes;
        }
    }
}