Merge class-level and method-level @Sql declarations
Prior to these commits method-level @Sql declarations always overrode class-level @Sql declarations, which required developers to redeclare class-level @Sql declarations on test methods (e.g., via copy-and-paste) in order to combine them with method-level @Sql declarations. These commits provide developers the ability to optionally merge class-level and method-level @Sql declarations via a new @SqlMergeMode annotation that can be applied at the class level or method level, with method-level declarations of @SqlMergeMode overriding class-level declarations. For example, @SqlMergeMode(MERGE) switches from the default OVERRIDE behavior to merging behavior, with class-level SQL scripts and statements executed before method-level SQL scripts and statements. Closes gh-1835
This commit is contained in:
commit
9cb15ba602
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
@ -31,7 +31,8 @@ import org.springframework.core.annotation.AliasFor;
|
|||
* SQL {@link #scripts} and {@link #statements} to be executed against a given
|
||||
* database during integration tests.
|
||||
*
|
||||
* <p>Method-level declarations override class-level declarations.
|
||||
* <p>Method-level declarations override class-level declarations by default,
|
||||
* but this behavior can be configured via {@link SqlMergeMode @SqlMergeMode}.
|
||||
*
|
||||
* <p>Script execution is performed by the {@link SqlScriptsTestExecutionListener},
|
||||
* which is enabled by default.
|
||||
|
@ -55,6 +56,7 @@ import org.springframework.core.annotation.AliasFor;
|
|||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
* @see SqlConfig
|
||||
* @see SqlMergeMode
|
||||
* @see SqlGroup
|
||||
* @see SqlScriptsTestExecutionListener
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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
|
||||
*
|
||||
* https://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 org.springframework.test.context.jdbc;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* {@code @SqlMergeMode} is used to annotate a test class or test method to
|
||||
* configure whether method-level {@code @Sql} declarations are merged with
|
||||
* class-level {@code @Sql} declarations.
|
||||
*
|
||||
* <p>A method-level {@code @SqlMergeMode} declaration overrides a class-level
|
||||
* declaration.
|
||||
*
|
||||
* <p>If {@code @SqlMergeMode} is not declared on a test class or test method,
|
||||
* {@link MergeMode#OVERRIDE} will be used by default.
|
||||
*
|
||||
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
|
||||
* <em>composed annotations</em> with attribute overrides.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Dmitry Semukhin
|
||||
* @since 5.2
|
||||
* @see Sql
|
||||
* @see MergeMode#MERGE
|
||||
* @see MergeMode#OVERRIDE
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface SqlMergeMode {
|
||||
|
||||
/**
|
||||
* Indicates whether method-level {@code @Sql} annotations should be merged
|
||||
* with class-level {@code @Sql} annotations or override them.
|
||||
*/
|
||||
MergeMode value();
|
||||
|
||||
|
||||
/**
|
||||
* Enumeration of <em>modes</em> that dictate whether method-level {@code @Sql}
|
||||
* declarations are merged with class-level {@code @Sql} declarations.
|
||||
*/
|
||||
enum MergeMode {
|
||||
|
||||
/**
|
||||
* Indicates that method-level {@code @Sql} declarations should be merged
|
||||
* with class-level {@code @Sql} declarations, with class-level SQL
|
||||
* scripts and statements executed before method-level scripts and
|
||||
* statements.
|
||||
*/
|
||||
MERGE,
|
||||
|
||||
/**
|
||||
* Indicates that method-level {@code @Sql} declarations should override
|
||||
* class-level {@code @Sql} declarations.
|
||||
*/
|
||||
OVERRIDE
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.test.context.jdbc;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -30,11 +31,13 @@ import org.springframework.core.io.ByteArrayResource;
|
|||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.jdbc.Sql.ExecutionPhase;
|
||||
import org.springframework.test.context.jdbc.SqlConfig.ErrorMode;
|
||||
import org.springframework.test.context.jdbc.SqlConfig.TransactionMode;
|
||||
import org.springframework.test.context.jdbc.SqlMergeMode.MergeMode;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.test.context.transaction.TestContextTransactionUtils;
|
||||
import org.springframework.test.context.util.TestContextResourceUtils;
|
||||
|
@ -81,6 +84,7 @@ import org.springframework.util.StringUtils;
|
|||
* locate these beans.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Dmitry Semukhin
|
||||
* @since 4.1
|
||||
* @see Sql
|
||||
* @see SqlConfig
|
||||
|
@ -108,7 +112,7 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
|
|||
* {@link TestContext} <em>before</em> the current test method.
|
||||
*/
|
||||
@Override
|
||||
public void beforeTestMethod(TestContext testContext) throws Exception {
|
||||
public void beforeTestMethod(TestContext testContext) {
|
||||
executeSqlScripts(testContext, ExecutionPhase.BEFORE_TEST_METHOD);
|
||||
}
|
||||
|
||||
|
@ -117,7 +121,7 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
|
|||
* {@link TestContext} <em>after</em> the current test method.
|
||||
*/
|
||||
@Override
|
||||
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||
public void afterTestMethod(TestContext testContext) {
|
||||
executeSqlScripts(testContext, ExecutionPhase.AFTER_TEST_METHOD);
|
||||
}
|
||||
|
||||
|
@ -125,22 +129,58 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
|
|||
* Execute SQL scripts configured via {@link Sql @Sql} for the supplied
|
||||
* {@link TestContext} and {@link ExecutionPhase}.
|
||||
*/
|
||||
private void executeSqlScripts(TestContext testContext, ExecutionPhase executionPhase) throws Exception {
|
||||
boolean classLevel = false;
|
||||
private void executeSqlScripts(TestContext testContext, ExecutionPhase executionPhase) {
|
||||
Method testMethod = testContext.getTestMethod();
|
||||
Class<?> testClass = testContext.getTestClass();
|
||||
|
||||
Set<Sql> sqlAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(
|
||||
testContext.getTestMethod(), Sql.class, SqlGroup.class);
|
||||
if (sqlAnnotations.isEmpty()) {
|
||||
sqlAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(
|
||||
testContext.getTestClass(), Sql.class, SqlGroup.class);
|
||||
if (!sqlAnnotations.isEmpty()) {
|
||||
classLevel = true;
|
||||
if (mergeSqlAnnotations(testContext)) {
|
||||
executeSqlScripts(getSqlAnnotationsFor(testClass), testContext, executionPhase, true);
|
||||
executeSqlScripts(getSqlAnnotationsFor(testMethod), testContext, executionPhase, false);
|
||||
}
|
||||
else {
|
||||
Set<Sql> methodLevelSqlAnnotations = getSqlAnnotationsFor(testMethod);
|
||||
if (!methodLevelSqlAnnotations.isEmpty()) {
|
||||
executeSqlScripts(methodLevelSqlAnnotations, testContext, executionPhase, false);
|
||||
}
|
||||
else {
|
||||
executeSqlScripts(getSqlAnnotationsFor(testClass), testContext, executionPhase, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Sql sql : sqlAnnotations) {
|
||||
executeSqlScripts(sql, executionPhase, testContext, classLevel);
|
||||
/**
|
||||
* Determine if method-level {@code @Sql} annotations should be merged with
|
||||
* class-level {@code @Sql} annotations.
|
||||
*/
|
||||
private boolean mergeSqlAnnotations(TestContext testContext) {
|
||||
SqlMergeMode sqlMergeMode = getSqlMergeModeFor(testContext.getTestMethod());
|
||||
if (sqlMergeMode == null) {
|
||||
sqlMergeMode = getSqlMergeModeFor(testContext.getTestClass());
|
||||
}
|
||||
return (sqlMergeMode != null && sqlMergeMode.value() == MergeMode.MERGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@code @SqlMergeMode} annotation declared on the supplied {@code element}.
|
||||
*/
|
||||
private SqlMergeMode getSqlMergeModeFor(AnnotatedElement element) {
|
||||
return AnnotatedElementUtils.findMergedAnnotation(element, SqlMergeMode.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@code @Sql} annotations declared on the supplied {@code element}.
|
||||
*/
|
||||
private Set<Sql> getSqlAnnotationsFor(AnnotatedElement element) {
|
||||
return AnnotatedElementUtils.getMergedRepeatableAnnotations(element, Sql.class, SqlGroup.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute SQL scripts for the supplied {@link Sql @Sql} annotations.
|
||||
*/
|
||||
private void executeSqlScripts(
|
||||
Set<Sql> sqlAnnotations, TestContext testContext, ExecutionPhase executionPhase, boolean classLevel) {
|
||||
|
||||
sqlAnnotations.forEach(sql -> executeSqlScripts(sql, executionPhase, testContext, classLevel));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,8 +193,8 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
|
|||
* @param testContext the current {@code TestContext}
|
||||
* @param classLevel {@code true} if {@link Sql @Sql} was declared at the class level
|
||||
*/
|
||||
private void executeSqlScripts(Sql sql, ExecutionPhase executionPhase, TestContext testContext, boolean classLevel)
|
||||
throws Exception {
|
||||
private void executeSqlScripts(
|
||||
Sql sql, ExecutionPhase executionPhase, TestContext testContext, boolean classLevel) {
|
||||
|
||||
if (executionPhase != sql.executionPhase()) {
|
||||
return;
|
||||
|
@ -166,15 +206,6 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
|
|||
mergedSqlConfig, executionPhase, testContext));
|
||||
}
|
||||
|
||||
final ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
|
||||
populator.setSqlScriptEncoding(mergedSqlConfig.getEncoding());
|
||||
populator.setSeparator(mergedSqlConfig.getSeparator());
|
||||
populator.setCommentPrefix(mergedSqlConfig.getCommentPrefix());
|
||||
populator.setBlockCommentStartDelimiter(mergedSqlConfig.getBlockCommentStartDelimiter());
|
||||
populator.setBlockCommentEndDelimiter(mergedSqlConfig.getBlockCommentEndDelimiter());
|
||||
populator.setContinueOnError(mergedSqlConfig.getErrorMode() == ErrorMode.CONTINUE_ON_ERROR);
|
||||
populator.setIgnoreFailedDrops(mergedSqlConfig.getErrorMode() == ErrorMode.IGNORE_FAILED_DROPS);
|
||||
|
||||
String[] scripts = getScripts(sql, testContext, classLevel);
|
||||
scripts = TestContextResourceUtils.convertToClasspathResourcePaths(testContext.getTestClass(), scripts);
|
||||
List<Resource> scriptResources = TestContextResourceUtils.convertToResourceList(
|
||||
|
@ -185,6 +216,8 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
|
|||
scriptResources.add(new ByteArrayResource(stmt.getBytes(), "from inlined SQL statement: " + stmt));
|
||||
}
|
||||
}
|
||||
|
||||
ResourceDatabasePopulator populator = createDatabasePopulator(mergedSqlConfig);
|
||||
populator.setScripts(scriptResources.toArray(new Resource[0]));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing SQL scripts: " + ObjectUtils.nullSafeToString(scriptResources));
|
||||
|
@ -225,13 +258,23 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
|
|||
TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
TransactionAttribute txAttr = TestContextTransactionUtils.createDelegatingTransactionAttribute(
|
||||
testContext, new DefaultTransactionAttribute(propagation));
|
||||
new TransactionTemplate(txMgr, txAttr).execute(status -> {
|
||||
populator.execute(finalDataSource);
|
||||
return null;
|
||||
});
|
||||
new TransactionTemplate(txMgr, txAttr).execute(() -> populator.execute(finalDataSource));
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private ResourceDatabasePopulator createDatabasePopulator(MergedSqlConfig mergedSqlConfig) {
|
||||
ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
|
||||
populator.setSqlScriptEncoding(mergedSqlConfig.getEncoding());
|
||||
populator.setSeparator(mergedSqlConfig.getSeparator());
|
||||
populator.setCommentPrefix(mergedSqlConfig.getCommentPrefix());
|
||||
populator.setBlockCommentStartDelimiter(mergedSqlConfig.getBlockCommentStartDelimiter());
|
||||
populator.setBlockCommentEndDelimiter(mergedSqlConfig.getBlockCommentEndDelimiter());
|
||||
populator.setContinueOnError(mergedSqlConfig.getErrorMode() == ErrorMode.CONTINUE_ON_ERROR);
|
||||
populator.setIgnoreFailedDrops(mergedSqlConfig.getErrorMode() == ErrorMode.IGNORE_FAILED_DROPS);
|
||||
return populator;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private DataSource getDataSourceFromTransactionManager(PlatformTransactionManager transactionManager) {
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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
|
||||
*
|
||||
* https://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 org.springframework.test.context.jdbc.merging;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.jdbc.EmptyDatabaseConfig;
|
||||
import org.springframework.test.context.jdbc.SqlMergeMode;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.annotation.DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD;
|
||||
|
||||
/**
|
||||
* Abstract base class for tests involving {@link SqlMergeMode @SqlMergeMode}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 5.2
|
||||
*/
|
||||
@ContextConfiguration(classes = EmptyDatabaseConfig.class)
|
||||
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
|
||||
abstract class AbstractSqlMergeModeTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
|
||||
protected void assertUsers(String... expectedUsers) {
|
||||
List<String> actualUsers = super.jdbcTemplate.queryForList("select name from user", String.class);
|
||||
assertThat(actualUsers).containsExactlyInAnyOrder(expectedUsers);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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
|
||||
*
|
||||
* https://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 org.springframework.test.context.jdbc.merging;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.test.context.jdbc.SqlMergeMode;
|
||||
|
||||
import static org.springframework.test.context.jdbc.SqlMergeMode.MergeMode.MERGE;
|
||||
import static org.springframework.test.context.jdbc.SqlMergeMode.MergeMode.OVERRIDE;
|
||||
|
||||
/**
|
||||
* Transactional integration tests that verify proper merging and overriding support
|
||||
* for class-level and method-level {@link Sql @Sql} declarations when
|
||||
* {@link SqlMergeMode @SqlMergeMode} is declared at the class level with
|
||||
* {@link SqlMergeMode.MergeMode#MERGE MERGE} mode.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Dmitry Semukhin
|
||||
* @since 5.2
|
||||
*/
|
||||
@Sql({ "../schema.sql", "../data-add-catbert.sql" })
|
||||
@SqlMergeMode(MERGE)
|
||||
public class ClassLevelMergeSqlMergeModeTests extends AbstractSqlMergeModeTests {
|
||||
|
||||
@Test
|
||||
public void classLevelScripts() {
|
||||
assertUsers("Catbert");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Sql("../data-add-dogbert.sql")
|
||||
public void merged() {
|
||||
assertUsers("Catbert", "Dogbert");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Sql({ "../schema.sql", "../data.sql", "../data-add-dogbert.sql", "../data-add-catbert.sql" })
|
||||
@SqlMergeMode(OVERRIDE)
|
||||
public void overridden() {
|
||||
assertUsers("Dilbert", "Dogbert", "Catbert");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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
|
||||
*
|
||||
* https://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 org.springframework.test.context.jdbc.merging;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.test.context.jdbc.SqlMergeMode;
|
||||
|
||||
import static org.springframework.test.context.jdbc.SqlMergeMode.MergeMode.MERGE;
|
||||
import static org.springframework.test.context.jdbc.SqlMergeMode.MergeMode.OVERRIDE;
|
||||
|
||||
/**
|
||||
* Transactional integration tests that verify proper merging and overriding support
|
||||
* for class-level and method-level {@link Sql @Sql} declarations when
|
||||
* {@link SqlMergeMode @SqlMergeMode} is declared at the class level with
|
||||
* {@link SqlMergeMode.MergeMode#OVERRIDE OVERRIDE} mode.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Dmitry Semukhin
|
||||
* @since 5.2
|
||||
*/
|
||||
@Sql({ "../schema.sql", "../data-add-catbert.sql" })
|
||||
@SqlMergeMode(OVERRIDE)
|
||||
public class ClassLevelOverrideSqlMergeModeTests extends AbstractSqlMergeModeTests {
|
||||
|
||||
@Test
|
||||
public void classLevelScripts() {
|
||||
assertUsers("Catbert");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Sql("../data-add-dogbert.sql")
|
||||
@SqlMergeMode(MERGE)
|
||||
public void merged() {
|
||||
assertUsers("Catbert", "Dogbert");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Sql({ "../schema.sql", "../data.sql", "../data-add-dogbert.sql", "../data-add-catbert.sql" })
|
||||
public void overridden() {
|
||||
assertUsers("Dilbert", "Dogbert", "Catbert");
|
||||
}
|
||||
|
||||
}
|
|
@ -419,6 +419,7 @@ Spring's testing annotations include the following:
|
|||
* <<spring-testing-annotation-aftertransaction>>
|
||||
* <<spring-testing-annotation-sql>>
|
||||
* <<spring-testing-annotation-sqlconfig>>
|
||||
* <<spring-testing-annotation-sqlmergemode>>
|
||||
* <<spring-testing-annotation-sqlgroup>>
|
||||
|
||||
[[spring-testing-annotation-bootstrapwith]]
|
||||
|
@ -968,9 +969,9 @@ it:
|
|||
----
|
||||
<1> Run two scripts for this test.
|
||||
|
||||
|
||||
See <<testcontext-executing-sql-declaratively>> for further details.
|
||||
|
||||
|
||||
[[spring-testing-annotation-sqlconfig]]
|
||||
===== `@SqlConfig`
|
||||
|
||||
|
@ -992,6 +993,56 @@ configured with the `@Sql` annotation. The following example shows how to use it
|
|||
<1> Set the comment prefix and the separator in SQL scripts.
|
||||
|
||||
|
||||
[[spring-testing-annotation-sqlmergemode]]
|
||||
===== `@SqlMergeMode`
|
||||
|
||||
`@SqlMergeMode` is used to annotate a test class or test method to configure whether
|
||||
method-level `@Sql` declarations are merged with class-level `@Sql` declarations. If
|
||||
`@SqlMergeMode` is not declared on a test class or test method, the `OVERRIDE` merge mode
|
||||
will be used by default. With the `OVERRIDE` mode, method-level `@Sql` declarations will
|
||||
effectively override class-level `@Sql` declarations.
|
||||
|
||||
Note that a method-level `@SqlMergeMode` declaration overrides a class-level declaration.
|
||||
|
||||
The following example shows how to use `@SqlMergeMode` at the class level.
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@SpringJUnitConfig(TestConfig.class)
|
||||
@Sql("/test-schema.sql")
|
||||
@SqlMergeMode(MERGE) <1>
|
||||
class UserTests {
|
||||
|
||||
@Test
|
||||
@Sql("/user-test-data-001.sql")
|
||||
void standardUserProfile {
|
||||
// execute code that relies on test data set 001
|
||||
}
|
||||
}
|
||||
----
|
||||
<1> Set the `@Sql` merge mode to `MERGE` for all test methods in the class.
|
||||
|
||||
The following example shows how to use `@SqlMergeMode` at the method level.
|
||||
|
||||
[source,java,indent=0]
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@SpringJUnitConfig(TestConfig.class)
|
||||
@Sql("/test-schema.sql")
|
||||
class UserTests {
|
||||
|
||||
@Test
|
||||
@Sql("/user-test-data-001.sql")
|
||||
@SqlMergeMode(MERGE) <1>
|
||||
void standardUserProfile {
|
||||
// execute code that relies on test data set 001
|
||||
}
|
||||
}
|
||||
----
|
||||
<1> Set the `@Sql` merge mode to `MERGE` for a specific test method.
|
||||
|
||||
|
||||
[[spring-testing-annotation-sqlgroup]]
|
||||
===== `@SqlGroup`
|
||||
|
||||
|
@ -1411,6 +1462,7 @@ You can use each of the following as a meta-annotation in conjunction with the
|
|||
* `@Rollback`
|
||||
* `@Sql`
|
||||
* `@SqlConfig`
|
||||
* `@SqlMergeMode`
|
||||
* `@SqlGroup`
|
||||
* `@Repeat` _(only supported on JUnit 4)_
|
||||
* `@Timed` _(only supported on JUnit 4)_
|
||||
|
@ -3997,11 +4049,16 @@ various `executeSqlScript(..)` methods for further details.
|
|||
In addition to the aforementioned mechanisms for running SQL scripts programmatically,
|
||||
you can declaratively configure SQL scripts in the Spring TestContext Framework.
|
||||
Specifically, you can declare the `@Sql` annotation on a test class or test method to
|
||||
configure the resource paths to SQL scripts that should be run against a given database
|
||||
before or after an integration test method. Note that method-level declarations override
|
||||
class-level declarations and that support for `@Sql` is provided by the
|
||||
`SqlScriptsTestExecutionListener`, which is enabled by default.
|
||||
configure individual SQL statements or the resource paths to SQL scripts that should be
|
||||
run against a given database before or after an integration test method. Support for
|
||||
`@Sql` is provided by the `SqlScriptsTestExecutionListener`, which is enabled by default.
|
||||
|
||||
NOTE: Method-level `@Sql` declarations override class-level declarations by default. As
|
||||
of Spring Framework 5.2, however, this behavior may be configured per test class or per
|
||||
test method via `@SqlMergeMode`. See
|
||||
<<testcontext-executing-sql-declaratively-script-merging>> for further details.
|
||||
|
||||
[[testcontext-executing-sql-declaratively-script-resources]]
|
||||
====== Path Resource Semantics
|
||||
|
||||
Each path is interpreted as a Spring `Resource`. A plain path (for example,
|
||||
|
@ -4034,10 +4091,11 @@ within a JUnit Jupiter based integration test class:
|
|||
}
|
||||
----
|
||||
|
||||
[[testcontext-executing-sql-declaratively-script-detection]]
|
||||
====== Default Script Detection
|
||||
|
||||
If no SQL scripts are specified, an attempt is made to detect a `default` script,
|
||||
depending on where `@Sql` is declared. If a default cannot be detected, an
|
||||
If no SQL scripts or statements are specified, an attempt is made to detect a `default`
|
||||
script, depending on where `@Sql` is declared. If a default cannot be detected, an
|
||||
`IllegalStateException` is thrown.
|
||||
|
||||
* Class-level declaration: If the annotated test class is `com.example.MyTest`, the
|
||||
|
@ -4046,6 +4104,7 @@ depending on where `@Sql` is declared. If a default cannot be detected, an
|
|||
defined in the class `com.example.MyTest`, the corresponding default script is
|
||||
`classpath:com/example/MyTest.testMethod.sql`.
|
||||
|
||||
[[testcontext-executing-sql-declaratively-multiple-annotations]]
|
||||
====== Declaring Multiple `@Sql` Sets
|
||||
|
||||
If you need to configure multiple sets of SQL scripts for a given test class or test
|
||||
|
@ -4088,6 +4147,7 @@ Java 7.
|
|||
}
|
||||
----
|
||||
|
||||
[[testcontext-executing-sql-declaratively-script-execution-phases]]
|
||||
====== Script Execution Phases
|
||||
|
||||
By default, SQL scripts are executed before the corresponding test method. However, if
|
||||
|
@ -4117,6 +4177,7 @@ following example shows:
|
|||
Note that `ISOLATED` and `AFTER_TEST_METHOD` are statically imported from
|
||||
`Sql.TransactionMode` and `Sql.ExecutionPhase`, respectively.
|
||||
|
||||
[[testcontext-executing-sql-declaratively-script-configuration]]
|
||||
====== Script Configuration with `@SqlConfig`
|
||||
|
||||
You can configure script parsing and error handling by using the `@SqlConfig` annotation.
|
||||
|
@ -4142,8 +4203,6 @@ provided by the `<jdbc:initialize-database/>` XML namespace element. See the jav
|
|||
individual attributes in {api-spring-framework}/test/context/jdbc/Sql.html[`@Sql`] and
|
||||
{api-spring-framework}/test/context/jdbc/SqlConfig.html[`@SqlConfig`] for details.
|
||||
|
||||
|
||||
|
||||
[[testcontext-executing-sql-declaratively-tx]]
|
||||
*Transaction management for `@Sql`*
|
||||
|
||||
|
@ -4208,6 +4267,18 @@ run, since any changes made to the database (either within the test method or wi
|
|||
`TransactionalTestExecutionListener` (see <<testcontext-tx,transaction management>> for
|
||||
details).
|
||||
|
||||
[[testcontext-executing-sql-declaratively-script-merging]]
|
||||
====== Merging and Overriding Configuration with `@SqlMergeMode`
|
||||
|
||||
As of Spring Framework 5.2, it is possible to merge method-level `@Sql` declarations with
|
||||
class-level declarations. For example, this allows you to provide the configuration for a
|
||||
database schema or some common test data once per test class and then provide additional,
|
||||
use case specific test data per test method. To enable `@Sql` merging, annotate either
|
||||
your test class or test method with `@SqlMergeMode(MERGE)`. To disable merging for a
|
||||
specific test method (or specific test subclass), you can switch back to the default mode
|
||||
via `@SqlMergeMode(OVERRIDE)`. Consult the <<spring-testing-annotation-sqlmergemode,
|
||||
`@SqlMergeMode` annotation documentation section>> for examples and further details.
|
||||
|
||||
|
||||
[[testcontext-parallel-test-execution]]
|
||||
==== Parallel Test Execution
|
||||
|
|
Loading…
Reference in New Issue