{
14 |
15 | private DbUnitInterceptor fieldInterceptor
16 |
17 | @Override
18 | void visitFieldAnnotation(DbUnit annotation, FieldInfo field) {
19 | if (fieldInterceptor) throw new ExtensionException("Expected maximum one field annotated with @DbUnit")
20 | if (annotation.content() != Object) throw new ExtensionException("Specifying the content of the database is only supported for annotations on a feature")
21 | fieldInterceptor = new DbUnitInterceptor(field, annotation)
22 | }
23 |
24 | @Override
25 | void visitFeatureAnnotation(DbUnit annotation, FeatureInfo feature) {
26 | def interceptor = new DbUnitInterceptor(feature, annotation)
27 | feature.spec.addSetupSpecInterceptor(interceptor)
28 | feature.spec.addSetupInterceptor(interceptor)
29 | feature.featureMethod.addInterceptor(interceptor)
30 | feature.spec.addCleanupInterceptor(interceptor)
31 |
32 | }
33 |
34 | @Override
35 | void visitSpec(SpecInfo spec) {
36 | //Note: spring integration works because the SpringExtension is a global extension and is executed before this one.
37 | if (fieldInterceptor) {
38 | spec.addSetupSpecInterceptor(fieldInterceptor)
39 | spec.addSetupInterceptor(fieldInterceptor)
40 | //add field interceptor only to those features that aren't annotated yet by any DbUnit annotation
41 | spec.features
42 | .findAll { f -> !f.featureMethod.reflection.annotations*.annotationType().contains(DbUnit) }
43 | .each { f -> f.featureMethod.addInterceptor(fieldInterceptor)
44 | }
45 | spec.addCleanupInterceptor(fieldInterceptor)
46 | }
47 | }
48 |
49 |
50 | }
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/src/test/groovy/be/janbols/spock/extension.dbunit/ConfigureTesterSpecification.groovy:
--------------------------------------------------------------------------------
1 | package be.janbols.spock.extension.dbunit
2 |
3 | import groovy.sql.Sql
4 |
5 | //
6 | import org.apache.tomcat.jdbc.pool.DataSource
7 | import org.dbunit.IDatabaseTester
8 | import org.dbunit.database.DatabaseConfig
9 | import org.dbunit.dataset.ReplacementDataSet
10 | import org.dbunit.ext.h2.H2DataTypeFactory
11 | import org.dbunit.operation.DatabaseOperation
12 | import org.joda.time.LocalDate
13 | import org.joda.time.LocalDateTime
14 | import org.springframework.beans.factory.annotation.Autowired
15 | import org.springframework.test.context.ContextConfiguration
16 | import spock.lang.Specification
17 |
18 | import static SpecUtils.createUserTable
19 | import static SpecUtils.dropUserTable
20 |
21 | /**
22 | * Specification showing how to configure the database by accessing the IDatabaseTester in the DbUnit#configure closure
23 | */
24 | @ContextConfiguration(locations = 'classpath:/spring/context.xml')
25 | class ConfigureTesterSpecification extends Specification {
26 |
27 | @Autowired
28 | DataSource dataSource
29 |
30 | @DbUnit(configure = { IDatabaseTester it ->
31 | //tell db unit how to setup and teardown the database
32 | it.setUpOperation = DatabaseOperation.CLEAN_INSERT
33 | it.tearDownOperation = DatabaseOperation.TRUNCATE_TABLE
34 |
35 | //tell db unit to replace all occurrences of [TOMORROW] with the real value
36 | (it.dataSet as ReplacementDataSet).addReplacementObject('[TOMORROW]', LocalDateTime.now().plusDays(1).toDate())
37 | //specify custom configurations if needed
38 | it.connection.config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new H2DataTypeFactory())
39 | })
40 | def content = {
41 | User(id: 1, name: 'janbols', created: '[NOW]', expiration: '[TOMORROW]')
42 | }
43 |
44 |
45 | def setup() {
46 | dataSource?.with { createUserTable(it) }
47 | }
48 |
49 | def cleanup() {
50 | dataSource?.with { dropUserTable(it) }
51 | }
52 |
53 |
54 | def "selecting from the User table returns the user"() {
55 | when:
56 | def result = new Sql(dataSource).firstRow("select * from User where name = 'janbols'")
57 | then:
58 | result.id == 1
59 | }
60 |
61 | def "the row in the User table returns has a created date of today and an expiration date of tomorrow"() {
62 | when:
63 | def result = new Sql(dataSource).firstRow("select * from User where name = 'janbols'")
64 | then:
65 | new LocalDate(result.created) == LocalDate.now()
66 | new LocalDate(result.expiration) == LocalDate.now().plusDays(1)
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/groovy/be/janbols/spock/extension/dbunit/support/DataSourceProvider.groovy:
--------------------------------------------------------------------------------
1 | package be.janbols.spock.extension.dbunit.support
2 |
3 | import be.janbols.spock.extension.dbunit.DbUnit
4 | import org.spockframework.runtime.extension.ExtensionException
5 | import org.spockframework.runtime.extension.IMethodInvocation
6 | import org.spockframework.util.ReflectionUtil
7 |
8 | import javax.sql.DataSource
9 |
10 | /**
11 | * Provides the datasource by calling the DbUnit.datasourceProvider closure or by looking for a shared or unshared DataSource field
12 | */
13 | class DataSourceProvider {
14 | private static final Class transactionAwareClass = ReflectionUtil.loadClassIfAvailable("org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy")
15 |
16 | private final DbUnit dbUnitAnnotation
17 | private IMethodInvocation setupSpecInvocation
18 | private IMethodInvocation setupInvocation
19 |
20 | DataSourceProvider(DbUnit dbUnitAnnotation) {
21 | this.dbUnitAnnotation = dbUnitAnnotation
22 | }
23 |
24 | def withSetupSpecInvocation(IMethodInvocation invocation) {
25 | this.setupSpecInvocation = invocation
26 | }
27 |
28 | def withSetupInvocation(IMethodInvocation invocation) {
29 | this.setupInvocation = invocation
30 | }
31 |
32 | DataSource findDataSource() {
33 | DataSource result = doFindDataSource(dbUnitAnnotation.datasourceProvider(), setupSpecInvocation)
34 | if (!result) {
35 | result = doFindDataSource(dbUnitAnnotation.datasourceProvider(), setupInvocation)
36 | }
37 |
38 | if (result) {
39 | result = makeTransactionalAware(result)
40 | }
41 |
42 | return result
43 | }
44 |
45 |
46 |
47 | private static DataSource doFindDataSource(Class extends Closure> dataSourceProviderClosureClass, IMethodInvocation invocation) {
48 | DataSource result
49 |
50 |
51 | if (dataSourceProviderClosureClass && Closure.isAssignableFrom(dataSourceProviderClosureClass)) {
52 | result = findDataSourceByProvider(dataSourceProviderClosureClass, invocation.instance)
53 | }
54 |
55 | if (!result) {
56 | result = findDataSourceByField(invocation)
57 | }
58 | return result
59 | }
60 |
61 | private static DataSource findDataSourceByField(IMethodInvocation iMethodInvocation) {
62 | def datasourceFieldInfo = iMethodInvocation.spec.allFields.find {
63 | return DataSource.isAssignableFrom(it.reflection.type)
64 | }
65 | return datasourceFieldInfo?.readValue(iMethodInvocation.instance)
66 | }
67 |
68 | private static DataSource findDataSourceByProvider(Class extends Closure> dataSourceProviderClass, Object target) {
69 | try {
70 | def dataSourceClosure = dataSourceProviderClass.newInstance(target, target)
71 | return dataSourceClosure();
72 | } catch (Exception e) {
73 | throw new ExtensionException("Failed to instantiate datasourceProvider in @DbUnit", e);
74 | }
75 | }
76 |
77 | /**
78 | * use transaction aware data source so changes are visible during the same @Transactional annotated feature
79 | */
80 | private static DataSource makeTransactionalAware(DataSource dataSource) {
81 | if (transactionAwareClass) {
82 | if(transactionAwareClass.isInstance(dataSource)) {
83 | return dataSource
84 | } else {
85 | return transactionAwareClass.newInstance(dataSource) as DataSource
86 | }
87 | } else {
88 | return dataSource
89 | }
90 | }
91 |
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/groovy/be/janbols/spock/extension/dbunit/DbUnit.groovy:
--------------------------------------------------------------------------------
1 | package be.janbols.spock.extension.dbunit
2 |
3 | import org.spockframework.runtime.extension.ExtensionAnnotation
4 |
5 | import javax.sql.DataSource
6 | import java.lang.annotation.ElementType
7 | import java.lang.annotation.Retention
8 | import java.lang.annotation.RetentionPolicy
9 | import java.lang.annotation.Target
10 |
11 | /**
12 | * Allows specifying the xml data as a closure field. This avoids the need to link to a separate xml file containing the xml data.
13 | * For this DbUnit needs to get hold of a {@link javax.sql.DataSource} either by returning it in the {@link DbUnit#datasourceProvider} method or by adding it as a field in the specification.
14 | * f.e.
15 | *
16 | class MyDbUnitTest extends Specification{
17 |
18 | DataSource dataSource
19 |
20 | {@literal @}DbUnit
21 | def content = {
22 | User(id: 1, name: 'jackdaniels', createdOn: '[NOW]')
23 | }
24 | ...
25 | }
26 |
27 | * The values for the collumns in the sql data are replaced using the {@link org.dbunit.dataset.ReplacementDataSet}. By default this is done for the keyword [NULL] and [NOW]
28 | */
29 | @Retention(RetentionPolicy.RUNTIME)
30 | @Target([ElementType.FIELD, ElementType.METHOD])
31 | @ExtensionAnnotation(DbUnitExtension.class)
32 | public @interface DbUnit {
33 | /**
34 | * Allows a {@link javax.sql.DataSource} to be provided inside the given closure. A dataSource can also be provided as a field of the test class. In that case you don't need to specify one in here.
35 | * @return A closure returning a {@link javax.sql.DataSource}
36 | */
37 | Class extends Closure> datasourceProvider() default Object.class;
38 |
39 | /**
40 | * Allows you to configure the {@link org.dbunit.IDatabaseTester} passed as the closure's argument.
41 | * This can be used f.e. to specify other {@link org.dbunit.operation.DatabaseOperation} for setup and teardown than the defaults.
42 | * This also allows you to specify the schema used or add a an operation listener.
43 | * Finally it allows you to specify replacements for the sql values you specified as the database tester is initially set up with a {@link org.dbunit.dataset.ReplacementDataSet}.
44 | * @return A closure with a IDatabaseTester as input argument configured with the data specified on the accompanying field.
45 | * @see org.dbunit.IDatabaseTester
46 | * @see org.dbunit.operation.DatabaseOperation
47 | * @see org.dbunit.AbstractDatabaseTester#setUpOperation
48 | * @see org.dbunit.AbstractDatabaseTester#tearDownOperation
49 | * @see org.dbunit.dataset.ReplacementDataSet
50 | */
51 | Class extends Closure> configure() default Object.class;
52 |
53 | /**
54 | * Name of the schema to use.
55 | * @return
56 | */
57 | String schema() default "";
58 |
59 | /**
60 | * Optional Closure containing the content of the database. This can only be used in a DbUnit annotation on a feature.
61 | * For DbUnit annotation on a field, the field itself is expected to contain the content.
62 | * f.e.
63 | *
64 | class MyDbUnitTest extends Specification{
65 |
66 | {@literal @}DbUnit(content = {
67 | User(id: 1, name: 'janbols')
68 | })
69 | def "feature with specific databasse content"() {
70 | ...
71 | }
72 |
73 | }
74 |
75 | * @return
76 | */
77 | Class extends Closure> content() default Object.class;
78 |
79 | /**
80 | * Enables "column sensing" feature of DBUnit,
81 | * where the list of columns for a table can vary - it is no longer deducted from the first row.
82 | */
83 | boolean columnSensing() default false;
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/groovy/be/janbols/spock/extension/dbunit/support/DbUnitFeatureInterceptor.groovy:
--------------------------------------------------------------------------------
1 | package be.janbols.spock.extension.dbunit.support
2 |
3 | import be.janbols.spock.extension.dbunit.DbUnit
4 | import org.dbunit.DataSourceDatabaseTester
5 | import org.dbunit.IDatabaseTester
6 | import org.spockframework.runtime.extension.AbstractMethodInterceptor
7 | import org.spockframework.runtime.extension.ExtensionException
8 | import org.spockframework.runtime.extension.IMethodInvocation
9 | import org.spockframework.runtime.model.FeatureInfo
10 | import org.spockframework.runtime.model.SpecInfo
11 |
12 | /**
13 | * Interceptor for setup and cleanup methods for DbUnit
14 | */
15 | class DbUnitFeatureInterceptor extends AbstractMethodInterceptor {
16 |
17 | private DataSourceDatabaseTester tester
18 | private final FeatureInfo featureInfo
19 | private final DbUnit dbUnitAnnotation
20 |
21 | private final DataSourceProvider dataSourceProvider
22 | private final DataSetProvider dataSetProvider
23 |
24 |
25 | DbUnitFeatureInterceptor(FeatureInfo featureInfo, DbUnit dbUnitAnnotation) {
26 | this.dbUnitAnnotation = dbUnitAnnotation
27 | this.featureInfo = featureInfo
28 | this.dataSetProvider = new DataSetProvider(dbUnitAnnotation, null)
29 | this.dataSourceProvider = new DataSourceProvider(dbUnitAnnotation)
30 | }
31 |
32 | @Override
33 | void interceptSetupSpecMethod(IMethodInvocation invocation) {
34 | invocation.proceed()
35 | dataSourceProvider.withSetupSpecInvocation(invocation)
36 | }
37 |
38 | @Override
39 | void interceptSetupMethod(IMethodInvocation invocation) {
40 | invocation.proceed()
41 |
42 | if (!featureInfo || featureInfo.featureMethod == invocation.feature.featureMethod) {
43 | dataSourceProvider.withSetupInvocation(invocation)
44 | //after setup to allow datasource setup
45 | def dataSource = dataSourceProvider.findDataSource()
46 | if (!dataSource) {
47 | throw new ExtensionException("Failed to find a javax.sql.DataSource. Specify one as a field or provide one using @DbUnit.datasourceProvider")
48 | }
49 |
50 | def dataSet = dataSetProvider.findDataSet(invocation.instance)
51 | if (!dataSet) {
52 | throw new ExtensionException("Failed to find a the data set. Specify one as a DbUnit-annotated field or provide one using @DbUnit.content")
53 | }
54 |
55 | tester = new DataSourceDatabaseTester(dataSource, dbUnitAnnotation.schema())
56 | tester.dataSet = dataSet
57 | configureTester(tester, invocation)
58 | tester.onSetup()
59 | }
60 | }
61 |
62 | @Override
63 | void interceptFeatureMethod(IMethodInvocation invocation) throws Throwable {
64 | invocation.proceed()
65 |
66 | }
67 |
68 | @Override
69 | void interceptFeatureExecution(IMethodInvocation invocation) throws Throwable {
70 | super.interceptFeatureExecution(invocation)
71 | }
72 |
73 | private void configureTester(IDatabaseTester tester, IMethodInvocation invocation) {
74 | def configureClosureClass = dbUnitAnnotation.configure()
75 | if (configureClosureClass && Closure.isAssignableFrom(configureClosureClass)) {
76 | try {
77 | def configureClosure = configureClosureClass.newInstance(invocation.instance, tester)
78 | configureClosure(tester);
79 | } catch (Exception e) {
80 | throw new ExtensionException("Failed to instantiate tester configurer in @DbUnit", e);
81 | }
82 | }
83 | }
84 |
85 |
86 | @Override
87 | void interceptCleanupMethod(IMethodInvocation invocation) {
88 | tester?.onTearDown()
89 | invocation.proceed()
90 | }
91 |
92 |
93 | void install(SpecInfo spec) {
94 | spec.addSetupInterceptor this
95 | spec.addSetupSpecInterceptor this
96 | spec.addCleanupInterceptor this
97 | }
98 |
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/groovy/be/janbols/spock/extension/dbunit/support/DbUnitInterceptor.groovy:
--------------------------------------------------------------------------------
1 | package be.janbols.spock.extension.dbunit.support
2 |
3 | import be.janbols.spock.extension.dbunit.DbUnit
4 | import org.dbunit.DataSourceDatabaseTester
5 | import org.dbunit.IDatabaseTester
6 | import org.dbunit.database.IDatabaseConnection
7 | import org.spockframework.runtime.extension.AbstractMethodInterceptor
8 | import org.spockframework.runtime.extension.ExtensionException
9 | import org.spockframework.runtime.extension.IMethodInvocation
10 | import org.spockframework.runtime.model.FeatureInfo
11 | import org.spockframework.runtime.model.FieldInfo
12 |
13 | /**
14 | * Interceptor for setup, feature and cleanup methods for DbUnit
15 | */
16 | class DbUnitInterceptor extends AbstractMethodInterceptor {
17 |
18 | private IDatabaseTester tester
19 | private final DbUnit dbUnitAnnotation
20 |
21 | private final DataSourceProvider dataSourceProvider
22 | private final DataSetProvider dataSetProvider
23 |
24 | DbUnitInterceptor(FieldInfo dataFieldInfo, DbUnit dbUnitAnnotation) {
25 | assert dataFieldInfo
26 | assert dbUnitAnnotation
27 | this.dbUnitAnnotation = dbUnitAnnotation
28 | this.dataSetProvider = new DataSetProvider(dbUnitAnnotation, dataFieldInfo)
29 | this.dataSourceProvider = new DataSourceProvider(dbUnitAnnotation)
30 | }
31 |
32 | DbUnitInterceptor(FeatureInfo featureInfo, DbUnit dbUnitAnnotation) {
33 | assert featureInfo
34 | assert dbUnitAnnotation
35 | this.dbUnitAnnotation = dbUnitAnnotation
36 | this.dataSetProvider = new DataSetProvider(dbUnitAnnotation, null)
37 | this.dataSourceProvider = new DataSourceProvider(dbUnitAnnotation)
38 | }
39 |
40 | @Override
41 | void interceptSetupSpecMethod(IMethodInvocation invocation) {
42 | invocation.proceed()
43 | dataSourceProvider.withSetupSpecInvocation(invocation)
44 | }
45 |
46 | @Override
47 | void interceptSetupMethod(IMethodInvocation invocation) {
48 | invocation.proceed()
49 | dataSourceProvider.withSetupInvocation(invocation)
50 | }
51 |
52 | volatile IDatabaseConnection currentConnection = null
53 |
54 | @Override
55 | void interceptFeatureMethod(IMethodInvocation invocation) throws Throwable {
56 | //after setup to allow datasource setup
57 | def dataSource = dataSourceProvider.findDataSource()
58 | if (!dataSource) {
59 | throw new ExtensionException("Failed to find a javax.sql.DataSource. Specify one as a field or provide one using @DbUnit.datasourceProvider")
60 | }
61 |
62 | def dataSet = dataSetProvider.findDataSet(invocation.instance)
63 | if (!dataSet) {
64 | throw new ExtensionException("Failed to find a the data set. Specify one as a DbUnit-annotated field or provide one using @DbUnit.content")
65 | }
66 |
67 | //override default behaviour of DataSourceDatabaseTester to always create new connections.
68 |
69 | //make sure to initialize schema to null when it's not specified. Otherwise a schema "" will be created instead of the default one
70 | //see https://github.com/janbols/spock-dbunit/issues/12
71 | tester = new DataSourceDatabaseTester(dataSource, dbUnitAnnotation.schema() ?: null ) {
72 | @Override
73 | IDatabaseConnection getConnection() throws Exception {
74 | if (!currentConnection || currentConnection.connection.isClosed()) {
75 | currentConnection = super.connection
76 | }
77 | return currentConnection
78 | }
79 |
80 | @Override
81 | void closeConnection(IDatabaseConnection connection) throws Exception {
82 | super.closeConnection(connection)
83 | currentConnection = null
84 | }
85 | }
86 | tester.dataSet = dataSet
87 | configureTester(tester, invocation)
88 | tester.onSetup()
89 |
90 | invocation.proceed()
91 | }
92 |
93 | private void configureTester(IDatabaseTester tester, IMethodInvocation invocation) {
94 | def configureClosureClass = dbUnitAnnotation.configure()
95 | if (configureClosureClass && Closure.isAssignableFrom(configureClosureClass)) {
96 | try {
97 | def configureClosure = configureClosureClass.newInstance(invocation.instance, tester)
98 | configureClosure(tester);
99 | } catch (Exception e) {
100 | throw new ExtensionException("Failed to instantiate tester configurer in @DbUnit", e);
101 | }
102 | }
103 | }
104 |
105 | @Override
106 | void interceptCleanupMethod(IMethodInvocation invocation) {
107 | tester?.onTearDown()
108 | invocation.proceed()
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/janbols/spock-dbunit)
2 | [ ](https://bintray.com/janbols/maven/spock-dbunit/0.4/link)
3 |
4 | spock-dbunit
5 | ============
6 |
7 | [Dbunit](http://dbunit.sourceforge.net/) extension for [spock](http://spockframework.org/) avoiding writing separate xml files
8 | when doing db related tests.
9 |
10 | Normally when using dbUnit, you specify your sql data in a separate xml file. This can become cumbersome
11 | and makes it more difficult to understand how your test is set up.
12 | You can avoid this using this spock extension.
13 |
14 | Using groovy's [MarkupBuilder](http://groovy-lang.org/processing-xml.html#_markupbuilder) you just specify your sql as a field
15 | like in the example below:
16 |
17 | ```groovy
18 | class MyDbUnitTest extends Specification{
19 |
20 | DataSource dataSource
21 |
22 | @DbUnit
23 | def content = {
24 | User(id: 1, name: 'jackdaniels', createdOn: '[NOW]')
25 | }
26 |
27 | ...
28 | ```
29 |
30 | The above code will setup dbUnit to insert the specified row in the User table.
31 | It will take the data source specified in the datasource field to get the connection to the database.
32 |
33 | Configuration
34 | -------------
35 | #### Finding the DataSource
36 | dbUnit needs a [DataSource](https://docs.oracle.com/javase/7/docs/api/javax/sql/DataSource.html) to connect to the database. There are several ways to do this:
37 | * by specifying a datasourceProvider as an extra closure parameter in the `@DbUnit` annotation. The closure returns a configured DataSource
38 | ```groovy
39 | class MyDbUnitTest extends Specification{
40 |
41 | @DbUnit(datasourceProvider = {
42 | inMemoryDataSource()
43 | })
44 | def content = {
45 | User(id: 1, name: 'janbols')
46 | }
47 |
48 | ...
49 | ```
50 | * by specifying a DataSource field in your specification
51 | ```groovy
52 | class MyDbUnitTest extends Specification{
53 |
54 | DataSource dataSource
55 |
56 | @DbUnit
57 | def content = {
58 | User(id: 1, name: 'janbols')
59 | }
60 |
61 | def setup() {
62 | dataSource = inMemoryDataSource()
63 | }
64 | ...
65 | ```
66 | * by specifying a `@Shared` DataSource field in your specification
67 | ```groovy
68 | class MyDbUnitTest extends Specification{
69 |
70 | @Shared DataSource dataSource
71 |
72 | @DbUnit def content = {
73 | User(id: 1, name: 'janbols')
74 | }
75 |
76 | def setupSpec(){
77 | dataSource = inMemoryDataSource()
78 | }
79 | ...
80 | ```
81 |
82 | #### Configuring the DatabaseTester
83 | The dbUnit [DatabaseTester](http://dbunit.sourceforge.net/apidocs/org/dbunit/IDatabaseTester.html)
84 | can also be configured as an extra closure in the `@DbUnit` annotation. An example can be seen below:
85 |
86 | ```groovy
87 | class MyDbUnitTest extends Specification{
88 |
89 | @DbUnit(configure={IDatabaseTester it ->
90 | it.setUpOperation = DatabaseOperation.CLEAN_INSERT
91 | it.tearDownOperation = DatabaseOperation.TRUNCATE_TABLE
92 |
93 | (it.dataSet as ReplacementDataSet)
94 | .addReplacementObject('[TOMORROW]', LocalDateTime.now().plusDays(1).toDate())
95 | })
96 | def content = {
97 | User(id: 1, name: 'jackdaniels', created: '[NOW]', expiration: '[TOMORROW]')
98 | }
99 |
100 | ...
101 | ```
102 |
103 | In the example above, the DatabaseTester is being configured to do a clean insert during setup and a table truncate during cleanup.
104 | In addition all `[TOMORROW]` fields are being replaced with the date of tomorrow.
105 |
106 | #### Specifying the schema
107 | You can specify the default schema using the `schema` field in the `DbUnit` annotation.
108 | The example below shows an example:
109 |
110 | ```groovy
111 | class MyDbUnitTest extends Specification{
112 |
113 | DataSource dataSource
114 |
115 | @DbUnit(schema = "otherSchema")
116 | def content = {
117 | User(id: 1, name: 'janbols')
118 | }
119 |
120 | ...
121 | ```
122 |
123 | #### Use different content per feature
124 | You can specify different database content per feature. This can be done by adding a `DbUnit` annotation
125 | on the feature method.
126 | The content can be specified in the `content` field of the `DbUnit` annotation.
127 | It accepts a closure that specifies the database content.
128 | When there's also a `DbUnit` annotation on a field containing database content,
129 | the one on the feature takes precedence and the one on the field is ignored.
130 | An example is shown below:
131 | ```groovy
132 | class MyDbUnitTest extends Specification{
133 |
134 | //default db content for all features that don't override this one
135 | @DbUnit
136 | def content = {
137 | User(id: 3, name: 'dinatersago')
138 | }
139 |
140 | ...
141 |
142 | //DbUnit on a feature overrides the one in the content field
143 | @DbUnit(content = {
144 | User(id: 1, name: 'janbols')
145 | })
146 | def "feature with own database content"() {
147 | ...
148 | }
149 |
150 | def "feature without own database content taking the content of the field"() {
151 | ...
152 | }
153 |
154 | ...
155 |
156 | ```
157 |
158 | Getting started
159 | ---
160 | To enable this Spock extension, you need to add a dependency to this project and a dependency to dbUnit
161 |
162 | using Maven:
163 |
164 | Enable the JCenter repository:
165 |
166 |
167 | jcenter
168 | JCenter Repo
169 | http://jcenter.bintray.com
170 |
171 | Add spock-reports to your :
172 |
173 |
174 | com.github.janbols
175 | spock-dbunit
176 | 0.4
177 | test
178 |
179 |
180 | org.dbunit
181 | dbunit
182 | 2.5.1
183 | test
184 |
185 |
186 |
187 | using Gradle:
188 |
189 | repositories {
190 | jcenter()
191 | }
192 |
193 | dependencies {
194 | testCompile 'com.github.janbols:spock-dbunit:0.4'
195 | testCompile 'org.dbunit:dbunit:2.5.1'
196 | }
197 |
198 | If you prefer, you can just download the jar directly
199 | from [JCenter](http://jcenter.bintray.com/com/github/janbols/spock-dbunit/0.4/:spock-dbunit-0.4.jar).
200 |
201 | Changes
202 | ---
203 | #### Version 0.4
204 | * Solve a bug that allows you to specify connection configuration properties (https://github.com/janbols/spock-dbunit/issues/9)
205 | * Solve a bug when no `DbUnit` annotation exists on a field but only on features (https://github.com/janbols/spock-dbunit/issues/10)
206 |
207 | #### Version 0.3
208 | * Be able to override the `DbUnit` content per feature (https://github.com/janbols/spock-dbunit/issues/7)
209 | * Be able to specify the schema (https://github.com/janbols/spock-dbunit/issues/6)
210 |
211 | #### Version 0.2
212 | * Easier way to see if spring-jdbc is on the classpath
213 | * Publish in bintray
214 |
215 | #### Version 0.1
216 | * Initial version
217 |
218 |
--------------------------------------------------------------------------------