From 5f6d5e55d1294ad8aee3be2d2a334dc8722040ba Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Thu, 30 Dec 2010 05:47:23 +0000 Subject: [PATCH] [SPR-7849] work in progress: revising the testing chapter based on internal review. git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3836 50f2f4bb-b051-0410-bef5-90022cba6387 --- spring-framework-reference/src/testing.xml | 326 +++++++++++---------- 1 file changed, 167 insertions(+), 159 deletions(-) diff --git a/spring-framework-reference/src/testing.xml b/spring-framework-reference/src/testing.xml index be128d6926d..6579505aa57 100644 --- a/spring-framework-reference/src/testing.xml +++ b/spring-framework-reference/src/testing.xml @@ -100,11 +100,12 @@ Spring's support for annotations such as - @Autowired and + @Autowired, + @Inject, and @Resource, which provides dependency injection for private or protected fields, setter methods, and - configuration methods + configuration methods. @@ -155,7 +156,7 @@ - The Spring Framework provides first class support for + The Spring Framework provides first-class support for integration testing in the spring-test module. The name of the actual jar file might include the release @@ -196,30 +197,28 @@ Goals of integration testing Spring's integration testing support has the following - goals: + primary goals: - Spring IoC container + To manage Spring IoC container caching between test execution. - Dependency Injection of + To provide Dependency Injection of test fixture instances. - Transaction management + To provide transaction management appropriate to integration testing. - Spring-specific - support classes that are useful in writing integration - tests. + To supply Spring-specific + base classes that assist developers in writing integration + tests. @@ -232,7 +231,7 @@ tests? Aren't these already provided?--> The Spring TestContext Framework provides consistent loading of Spring ApplicationContexts and caching of those contexts. Support for the caching of loaded contexts is important, - because startup time can become an issue - not because of the overhead + because startup time can become an issue — not because of the overhead of Spring itself, but because the objects instantiated by the Spring container take time to instantiate. For example, a project with 50 to 100 Hibernate mapping files might take 10 to 20 seconds to load the @@ -241,7 +240,7 @@ tests? Aren't these already provided?--> productivity. Test classes provide an array containing the resource locations - of XML configuration metadata - typically in the classpath - that is + of XML configuration metadata — typically in the classpath — that is used to configure the application. These locations are the same as or similar to the list of configuration locations specified in web.xml or other deployment configuration @@ -251,9 +250,9 @@ tests? Aren't these already provided?--> ApplicationContext is reused for each test. Thus the setup cost is incurred only once (per test fixture), and subsequent test execution is much faster. In the unlikely case - that a test corrupts the application context and requires reloading -- - for example, by changing a bean definition or the state of an - application object-- a Spring testing support mechanism causes the + that a test corrupts the application context and requires reloading — + for example, by modifying a bean definition or the state of an + application object — a Spring testing support mechanism causes the test fixture to reload the configurations and rebuilds the application context before executing the next test. @@ -273,8 +272,7 @@ tests? Aren't these already provided?--> contexts across various testing scenarios (e.g., for configuring Spring-managed object graphs, transactional proxies, DataSources, etc.), thus avoiding the need to - duplicate complex test fixture set up for individual test - cases. + duplicate complex test fixture set up for individual test cases. As an example, consider the scenario where we have a class, HibernateTitleDao, that performs data access @@ -292,7 +290,7 @@ tests? Aren't these already provided?--> The Hibernate mapping file configuration: is everything - mapped correctly and are the correct lazy-loading settings in + mapped correctly, and are the correct lazy-loading settings in place? @@ -303,7 +301,7 @@ tests? Aren't these already provided?--> - See: dependency injection of test fixtures with the See dependency injection of test fixtures with the TestContext Framework. @@ -313,8 +311,8 @@ tests? Aren't these already provided?--> One common issue in tests that access a real database is their affect on the state of the persistence store. Even when you're using a development database, changes to the state may affect future tests. - Also, many operations - such as inserting or modifying persistent data - - cannot be performed (or verified) outside a transaction. + Also, many operations — such as inserting or modifying persistent data + — cannot be performed (or verified) outside a transaction. The TestContext framework addresses this issue. By default, the framework will create and roll back a transaction for each test. You @@ -328,9 +326,9 @@ tests? Aren't these already provided?--> a PlatformTransactionManager bean defined in the test's application context. - If you want a transaction to commit - unusual, but occasionally + If you want a transaction to commit — unusual, but occasionally useful when you want a particular test to populate or modify the - database - the TestContext framework can be instructed to cause the + database — the TestContext framework can be instructed to cause the transaction to commit instead of roll back via the @TransactionConfiguration and - A SimpleJdbcTemplate, for querying to - confirm state. For example, you use an ORM tool to query before - and after testing application code that creates an object and - persists it, - to verify that the data appears in the database. (Spring ensures - that the query runs in the scope of the same transaction.) You - need to tell your ORM tool to 'flush' its changes, by using, for - example, the flush() method on - Hibernate's Session - interface. + A SimpleJdbcTemplate, for executing + SQL statements to query the database. + Such queries can be used to confirm database state both + prior to and after + execution of database-related application code, and Spring + ensures that such queries run in the scope of the same + transaction as the application code. When used in conjunction + with an ORM tool, be sure to avoid + false positives. @@ -398,9 +395,7 @@ tests? Aren't these already provided?-->
- Annotations<!--See highlighted area directly below with double-lined bar: what does this mean? Is something missing?--> - - + Annotations The Spring Framework provides the following set of Spring-specific annotations that you can use in @@ -421,7 +416,7 @@ tests? Aren't these already provided?--> well as the ContextLoader strategy to use for loading the context. - @ContextConfiguration(locations={"example/test-context.xml"}, loader=CustomContextLoader.class) + @ContextConfiguration(locations="example/test-context.xml", loader=CustomContextLoader.class) public class CustomConfiguredApplicationContextTests { // class body... } @@ -441,9 +436,11 @@ public class CustomConfiguredApplicationContextTests { Indicates that the underlying Spring ApplicationContext has been - dirtied (modified)as - follows during the execution of a test and should be closed, - regardless of whether the test passed: + dirtied (i.e., modified or corrupted in some manner) + during the execution of a test and should be closed, + regardless of whether the test passed. + @DirtiesContext is supported in + the following scenarios: @@ -467,23 +464,26 @@ public class CustomConfiguredApplicationContextTests { example, by replacing a bean definition). Subsequent tests are supplied a new context. - + Limitations of - <interfacename>@DirtiesContext</interfacename> with JUnit - 3.8<!--JUnit 3.8 and earlier? Later? ONLY JUnit 3.8? Specify.--> + @DirtiesContext at the class level - In a JUnit 3.8 environment + JUnit 4+ and TestNG both support class-level lifecycle + callbacks — for example, via @BeforeClass + and @AfterClass annotations. Consequently, + @DirtiesContext can be used at the class level + with these frameworks. JUnit 3.x, however, does not support + before class or after class + lifecycle callbacks. Thus, in a JUnit 3.x environment @DirtiesContext is only supported - on methods and thus not at the class level. - - - You can use @DirtiesContext as - a class-level and method-level annotation within the same class. - In - such scenarios, the - ApplicationContext is marked as + If class-level usage of @DirtiesContext + is supported (e.g., with JUnit 4.5+ or TestNG), you can use + @DirtiesContext as both a class-level + and method-level annotation within the same test class. In such scenarios, + the ApplicationContext is marked as dirty after any such annotated method as well as after the entire class. If the ClassMode is set to AFTER_EACH_TEST_METHOD, the context is @@ -518,7 +518,7 @@ public void testProcessWhichDirtiesAppCtx() { Defines class-level metadata for configuring which TestExecutionListeners should be - registered with a TestContextManager. + registered with the TestContextManager. Typically, @TestExecutionListeners are used in conjunction with @ContextConfiguration. @@ -542,8 +542,8 @@ public class CustomTestExecutionListenerTests { tests. Specifically, the bean name of the PlatformTransactionManager that is to be used to drive transactions can be explicitly configured if the - bean name of the desired PlatformTransactionManager is not - "transactionManager". In addition, you can change the + bean name of the desired PlatformTransactionManager + is not "transactionManager". In addition, you can change the defaultRollback flag to false. Typically, @TransactionConfiguration is used in conjunction with @@ -554,6 +554,17 @@ public class CustomTestExecutionListenerTests { public class CustomConfiguredTransactionalTests { // class body... } + + + If the default conventions are sufficient for your + test configuration, you can avoid using + @TransactionConfiguration + altogether. In other words, if your transaction + manager bean is named "transactionManager" and if you want + transactions to roll back automatically, there is no need + to annotate your test class with + @TransactionConfiguration. + @@ -635,15 +646,13 @@ public void testProcessWithoutTransaction() { @Transactional; doing so allows a mix of transactional and non-transactional methods in the same test class without the need for using - @NotTransactional. + @NotTransactional. - - The following annotations are only supported - when used in conjunction with JUnit (that is., with the SpringJUnit4ClassRunner or the JUnit 3.8.2 and The scope of execution to be repeated includes execution of the test method itself as well as any set up or - tear down of the test fixture. + tear down of the test fixture. @Repeat(10) @Test @@ -781,8 +790,6 @@ public void testProcessRepeatedly() { - - The following non-test-specific annotations are supported with standard semantics for all configurations of the Spring TestContext Framework. @@ -878,8 +885,6 @@ public void testProcessRepeatedly() { linkend="integration-testing-annotations">annotation support sections. - -
Key abstractions @@ -912,10 +917,29 @@ public void testProcessRepeatedly() { which manages a single TestContext and signals events to all registered TestExecutionListeners at - well-defined test execution points: test instance preparation, - prior to any before methods of a particular - testing framework, and after any after - methods of a particular testing framework. + well-defined test execution points: + + + + prior to any before class methods + of a particular testing framework + + + test instance preparation + + + prior to any before methods + of a particular testing framework + + + after any after methods + of a particular testing framework + + + after any after class methods + of a particular testing framework + + @@ -928,14 +952,13 @@ public void testProcessRepeatedly() { Spring provides three TestExecutionListener implementations that are configured by default: - DependencyInjectionTestExecutionListener, - DirtiesContextTestExecutionListener, and + DependencyInjectionTestExecutionListener, + DirtiesContextTestExecutionListener, and TransactionalTestExecutionListener. Respectively, they support dependency injection of the test instance, handling of the @DirtiesContext annotation, and - transactional test execution with default rollback - semantics. + transactional test execution with default rollback semantics. @@ -945,8 +968,6 @@ public void testProcessRepeatedly() { with the framework.
- -
Context management and caching @@ -1018,8 +1039,8 @@ public class MyTest { @ContextConfiguration with an array that contains the resource locations of XML configuration metadata (assuming an XML-capable ContextLoader - has been configured) - typically in the classpath - - used to configure the application. (See the following code example.) + has been configured) — typically in the classpath + — used to configure the application. (See the following code example.) This location will be the same, or nearly the same, as the list of configuration locations specified in web.xml or other deployment configuration. Alternatively, you can implement and @@ -1082,8 +1103,8 @@ public class ExtendedTest extends BaseTest { test. Thus the setup cost is incurred only once (per test fixture), and subsequent test execution is much faster. In the unlikely case that a test dirties (modifies) - the application context, requiring reloading -- for example, by - changing a bean definition or the state of an application object -- + the application context, requiring reloading — for example, by + changing a bean definition or the state of an application object — you can annotate your test method with @DirtiesContext (assuming DirtiesContextTestExecutionListener has been @@ -1092,15 +1113,13 @@ public class ExtendedTest extends BaseTest { executing the next test.
- -
Dependency Injection of test fixtures When you configure the - DependencyInjectionTestExecutionListener -- + DependencyInjectionTestExecutionListener — which is configured by default through the - @TestExecutionListeners annotation-- + @TestExecutionListeners annotation — the dependencies of your test instances are injected from beans in the application context you configured through @@ -1154,7 +1173,8 @@ public class ExtendedTest extends BaseTest { linkend="testing-fixture-di">Goals section. (We will look at the application context configuration after all sample code listings.) A JUnit 4-based implementation of the test class itself uses - @Autowired for field injection. + @Autowired for field injection. + The dependency injection behavior in the following code @@ -1186,8 +1206,6 @@ public final class HibernateTitleDaoTests { } } - - Alternatively, you can configure the class to use @Autowired for setter injection. @@ -1211,8 +1229,6 @@ public final class HibernateTitleDaoTests { } } - - Here is an example of @Resource for field injection. @@ -1232,8 +1248,6 @@ public final class HibernateTitleDaoTests { } } - - Here is an example of @Resource for setter injection. @@ -1257,8 +1271,6 @@ public final class HibernateTitleDaoTests { } } - - The preceding code listings use the same XML context file referenced by the @ContextConfiguration annotation (that is, daos.xml), which looks like @@ -1313,12 +1325,14 @@ public final class HibernateTitleDaoTests { assuming that "myDataSource" is the bean id). If there is only one DataSource bean to begin with, then the qualifier does not have any effect, independent from the bean - name of that single matching bean. + name of that single matching bean. + Alternatively, consider using the @Resource annotation on such overridden setter methods, defining the target bean name explicitly, - with no type matching semantics. Note that this always + with no type matching semantics. Note that this + always points to a bean with that specific name, no matter whether there is one or more beans of the given type. @@ -1334,8 +1348,6 @@ public final class HibernateTitleDaoTests {
- -
Transaction management @@ -1409,7 +1421,8 @@ public final class HibernateTitleDaoTests { integration testing scenario highlighting several transaction-related annotations. Consult the annotation support - section of the reference manual for + section of the reference manual + for further information and configuration examples. @RunWith(SpringJUnit4ClassRunner.class) @@ -1447,13 +1460,17 @@ public class FictitiousTransactionalTest { } + Avoid false positives when testing ORM code When you test code involving an ORM framework such as JPA or Hibernate, flush the underlying session within - test methods which update the state of the + test methods + which update the state of the session. Failing to flush the ORM framework's underlying session can produce false positives: your test may pass, but the same code throws an exception in a live, production @@ -1484,8 +1501,6 @@ public void updateWithSessionFlush() {
- -
TestContext support classes @@ -1505,11 +1520,12 @@ public void updateWithSessionFlush() { JUnit 3.8 environment. When you extend the AbstractJUnit38SpringContextTests class, you need access to the following protected - instance variables: + instance variables: + @@ -1543,18 +1559,15 @@ to variables. i.e. extending class is what gives you access.--> - simpleJdbcTemplate: Useful for - querying to confirm state. For example, use an ORM tool to - query before and after testing application code that creates - an object and persists it, to - verify that the data appears in the database. (Spring - ensures that the query runs in the scope of the same - transaction.) You need to tell your ORM tool to 'flush' its - changes for this to work correctly by, for example, using - the flush() method on Hibernate's - Session interface. + simpleJdbcTemplate: Use this variable + to execute SQL statements to query the database. + Such queries can be used to confirm database state both + prior to and after + execution of database-related application code, and Spring + ensures that such queries run in the scope of the same + transaction as the application code. When used in conjunction + with an ORM tool, be sure to avoid + false positives. @@ -1607,21 +1620,21 @@ code, etc? Or what? If my rewording is wrong, revise to clarify. What does using applicationContext: Inherited from the AbstractJUnit4SpringContextTests - superclass. Perform explicit bean lookups or test the state - of the context as a whole. + superclass. Use this variable to perform explicit bean + lookups or to test the state of the context as a + whole. - simpleJdbcTemplate: Useful for - querying to confirm state. For example, use an ORM tool to - query before and after testing application code that creates - an object and persists it, to verify that the data appears - in the database. (Spring - ensures that the query runs in the scope of the same - transaction.) You need to tell your ORM tool to 'flush' its - changes for this to work correctly by, for example, using - the flush() method on Hibernate's - Session interface. + simpleJdbcTemplate: Use this variable + to execute SQL statements to query the database. + Such queries can be used to confirm database state both + prior to and after + execution of database-related application code, and Spring + ensures that such queries run in the scope of the same + transaction as the application code. When used in conjunction + with an ORM tool, be sure to avoid + false positives. @@ -1630,8 +1643,8 @@ code, etc? Or what? If my rewording is wrong, revise to clarify. What does using These classes are a convenience for extension. If you do not want your test classes to be tied to a Spring-specific class - hierarchy -- for example, if you want to extend directly the class - you are testing -- you can configure your own custom test classes + hierarchy — for example, if you want to extend directly the class + you are testing — you can configure your own custom test classes by using @RunWith(SpringJUnit4ClassRunner.class), @ContextConfiguration, @@ -1714,21 +1727,21 @@ public class SimpleTest { applicationContext: Inherited from the AbstractTestNGSpringContextTests - superclass. Perform explicit bean lookups or test the state - of the context as a whole. + superclass. Use this variable to perform explicit bean + lookups or to test the state of the context as a + whole. - simpleJdbcTemplate: Useful for - querying to confirm state. For example, use an ORM tool to - query before and after testing application code that creates - an object and persists it, to verify that the data appears - in the database. (Spring ensures that the query runs in the - scope of the same transaction.) You need to tell your ORM - tool to 'flush' its changes for this to work correctly by, - for example, using the flush() - method on Hibernate's Session - interface. + simpleJdbcTemplate: Use this variable + to execute SQL statements to query the database. + Such queries can be used to confirm database state both + prior to and after + execution of database-related application code, and Spring + ensures that such queries run in the scope of the same + transaction as the application code. When used in conjunction + with an ORM tool, be sure to avoid + false positives. @@ -1737,8 +1750,8 @@ public class SimpleTest { These classes are a convenience for extension. If you do not want your test classes to be tied to a Spring-specific class - hierarchy--for example, if you want to directly extend the class - you are testing--you can configure your own custom test classes by + hierarchy — for example, if you want to directly extend the class + you are testing — you can configure your own custom test classes by using @ContextConfiguration, @TestExecutionListeners, and so on, and by manually instrumenting your test class with a @@ -1748,12 +1761,8 @@ public class SimpleTest {
- - - -
PetClinic example @@ -1802,8 +1811,8 @@ public abstract class AbstractClinicTests extends Abstract - The clinic instance variable - the - application object being tested - is set by Dependency Injection + The clinic instance variable — the + application object being tested — is set by Dependency Injection through @Autowired semantics. @@ -1821,8 +1830,9 @@ public abstract class AbstractClinicTests extends Abstract Like many integration tests that use a database, most of the tests in AbstractClinicTests depend on a minimum amount of data already in the database before the test cases - run. You might, however, choose to populate the database in your - test cases also - again, within the same transaction. + run. You might, however, choose to populate the database in + your + test cases also — again, within the same transaction. @@ -1863,7 +1873,7 @@ public class HibernateClinicTests extends AbstractClinicTests { } is typical of large-scale applications, configuration locations are often specified in a common base class for all application-specific integration tests. Such a base class may also add useful instance - variables--populated by Dependency Injection, naturally--such as a + variables — populated by Dependency Injection, naturally — such as a HibernateTemplate, in the case of an application using Hibernate. @@ -1888,8 +1898,6 @@ public class HibernateClinicTests extends AbstractClinicTests { } files for connection settings: see the PetClinic application for an example.
- -