You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1931 lines
92 KiB
1931 lines
92 KiB
<?xml version="1.0" encoding="UTF-8"?> |
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" |
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"> |
|
<chapter id="testing"> |
|
<title>Testing</title> |
|
|
|
<section id="testing-introduction"> |
|
<title>Introduction</title> |
|
|
|
<para>The Spring team considers developer testing to be an absolutely |
|
integral part of enterprise software development. A thorough treatment of |
|
testing in the enterprise is beyond the scope of this chapter; rather, the |
|
focus here is on the value-add that the adoption of the IoC principle can |
|
bring to <link linkend="unit-testing">unit testing</link> and on the |
|
benefits that the Spring Framework provides in <link |
|
linkend="integration-testing">integration testing</link>.</para> |
|
</section> |
|
|
|
<section id="unit-testing"> |
|
<title>Unit testing</title> |
|
|
|
<para>One of the main benefits of Dependency Injection is that your code |
|
should really depend far less on the container than in traditional Java EE |
|
development. The POJOs that make up your application should be testable in |
|
JUnit or TestNG tests, with objects simply instantiated using the |
|
<literal>new</literal> operator, <emphasis>without Spring or any other |
|
container</emphasis>. You can use <link linkend="mock-objects">mock |
|
objects</link> (in conjunction with many other valuable testing |
|
techniques) to test your code in isolation. If you follow the architecture |
|
recommendations around Spring you will find that the resulting clean |
|
layering and componentization of your codebase will naturally facilitate |
|
<emphasis>easier</emphasis> unit testing. For example, you will be able to |
|
test service layer objects by stubbing or mocking DAO or Repository |
|
interfaces, without any need to access persistent data while running unit |
|
tests.</para> |
|
|
|
<para>True unit tests typically will run extremely quickly, as there is no |
|
runtime infrastructure to set up, whether application server, database, |
|
ORM tool, or whatever. Thus emphasizing true unit tests as part of your |
|
development methodology will boost your productivity. The upshot of this |
|
is that you often do not need this section of the testing chapter to help |
|
you write effective <emphasis>unit</emphasis> tests for your IoC-based |
|
applications. For certain unit testing scenarios, however, the Spring |
|
Framework provides the following mock objects and testing support |
|
classes.</para> |
|
|
|
<section id="mock-objects"> |
|
<title>Mock objects</title> |
|
|
|
<section id="mock-objects-jndi"> |
|
<title>JNDI</title> |
|
|
|
<para>The <literal>org.springframework.mock.jndi</literal> package |
|
contains an implementation of the JNDI SPI, which is useful for |
|
setting up a simple JNDI environment for test suites or stand-alone |
|
applications. If, for example, JDBC <classname>DataSource</classname>s |
|
get bound to the same JNDI names in test code as within a Java EE |
|
container, both application code and configuration can be reused in |
|
testing scenarios without modification.</para> |
|
</section> |
|
|
|
<section id="mock-objects-servlet"> |
|
<title>Servlet API</title> |
|
|
|
<para>The <literal>org.springframework.mock.web</literal> package |
|
contains a comprehensive set of Servlet API mock objects, targeted at |
|
usage with Spring's Web MVC framework, which are useful for testing |
|
web contexts and controllers. These mock objects are generally more |
|
convenient to use than dynamic mock objects (e.g., <ulink |
|
url="http://www.easymock.org">EasyMock</ulink>) or existing Servlet |
|
API mock objects (e.g., <ulink |
|
url="http://www.mockobjects.com">MockObjects</ulink>).</para> |
|
</section> |
|
|
|
<section id="mock-objects-portlet"> |
|
<title>Portlet API</title> |
|
|
|
<para>The <literal>org.springframework.mock.web.portlet</literal> |
|
package contains a set of Portlet API mock objects, targeted at usage |
|
with Spring's Portlet MVC framework.</para> |
|
</section> |
|
</section> |
|
|
|
<section id="unit-testing-support-classes"> |
|
<title>Unit testing support classes</title> |
|
|
|
<section id="unit-testing-utilities"> |
|
<title>General utilities</title> |
|
|
|
<para>The <literal>org.springframework.test.util</literal> package |
|
contains <classname>ReflectionTestUtils</classname>, which is a |
|
collection of reflection-based utility methods for use in unit and |
|
integration testing scenarios in which the developer would benefit |
|
from being able to set a non-<literal>public</literal> field or invoke |
|
a non-<literal>public</literal> setter method when testing application |
|
code involving, for example:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>ORM frameworks such as JPA and Hibernate which condone the |
|
usage of <literal>private</literal> or |
|
<literal>protected</literal> field access as opposed to |
|
<literal>public</literal> setter methods for properties in a |
|
domain entity</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Spring's support for annotations such as |
|
<interfacename>@Autowired</interfacename> and |
|
<interfacename>@Resource</interfacename> which provides dependency |
|
injection for <literal>private</literal> or |
|
<literal>protected</literal> fields, setter methods, and |
|
configuration methods</para> |
|
</listitem> |
|
</itemizedlist> |
|
</section> |
|
|
|
<section id="unit-testing-spring-mvc"> |
|
<title>Spring MVC</title> |
|
|
|
<para>The <literal>org.springframework.test.web</literal> package |
|
contains <classname>ModelAndViewAssert</classname>, which can be used |
|
in combination with any testing framework (e.g., JUnit 4+, TestNG, |
|
etc.) for unit tests dealing with Spring MVC |
|
<classname>ModelAndView</classname> objects.</para> |
|
|
|
<tip> |
|
<title>Unit testing Spring MVC Controllers</title> |
|
|
|
<para>To test your Spring MVC <literal>Controller</literal>s, use |
|
<classname>ModelAndViewAssert</classname> combined with |
|
<literal>MockHttpServletRequest</literal>, |
|
<literal>MockHttpSession</literal>, etc. from the <link |
|
linkend="mock-objects-servlet"><literal>org.springframework.mock.web</literal></link> |
|
package.</para> |
|
</tip> |
|
</section> |
|
</section> |
|
</section> |
|
|
|
<section id="integration-testing"> |
|
<title>Integration testing</title> |
|
|
|
<section id="integration-testing-overview"> |
|
<title>Overview</title> |
|
|
|
<para>It is important to be able to perform some integration testing |
|
without requiring deployment to your application server or connecting to |
|
other enterprise infrastructure. This will enable you to test things |
|
such as:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>The correct wiring of your Spring IoC container |
|
contexts.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Data access using JDBC or an ORM tool. This would include such |
|
things as the correctness of SQL statements, Hibernate queries, JPA |
|
entity mappings, etc.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>The Spring Framework provides first class support for integration |
|
testing in the <filename |
|
class="libraryfile">org.springframework.test-VERSION.jar</filename> |
|
library (where <literal>VERSION</literal> is the release version). In |
|
this library, you will find the |
|
<literal>org.springframework.test</literal> package which contains |
|
valuable classes for integration testing using a Spring container, while |
|
at the same time not being reliant on an application server or other |
|
deployment environment. Such tests will be slower to run than unit tests |
|
but much faster to run than the equivalent Cactus tests or remote tests |
|
relying on deployment to an application server.</para> |
|
|
|
<para>Since Spring 2.5, unit and integration testing support is provided |
|
in the form of the annotation-driven <link |
|
linkend="testcontext-framework">Spring TestContext Framework</link>. The |
|
TestContext Framework is agnostic of the actual testing framework in |
|
use, thus allowing instrumentation of tests in various environments |
|
including JUnit, TestNG, etc.</para> |
|
|
|
<note> |
|
<title>Legacy JUnit 3.8 class hierarchy is deprecated</title> |
|
|
|
<para>As of Spring 3.0, the legacy JUnit 3.8 base class hierarchy |
|
(e.g., |
|
<classname>AbstractDependencyInjectionSpringContextTests</classname>, |
|
<classname>AbstractTransactionalDataSourceSpringContextTests</classname>, |
|
etc.) is officially deprecated and will be removed in a later release. |
|
Thus any code which depends on the legacy JUnit 3.8 support should be |
|
migrated to the <link linkend="testcontext-framework">Spring |
|
TestContext Framework</link>.</para> |
|
</note> |
|
</section> |
|
|
|
<section id="integration-testing-goals"> |
|
<title>Goals</title> |
|
|
|
<para>The following bullet points highlight the fundamental goals of |
|
Spring's integration testing support:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><link linkend="testing-ctx-management">Spring IoC container |
|
caching</link> between test execution.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><link linkend="testing-fixture-di">Dependency Injection of |
|
test fixture instances</link> (this is nice).</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><link linkend="testing-tx">Transaction management</link> |
|
appropriate to integration testing (this is even nicer).</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><link linkend="testing-support-classes">Spring-specific |
|
support classes</link> that are really useful when writing |
|
integration tests.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>In the next few sections each of the above goals is discussed in |
|
greater detail, and at the end of each section you will find a direct |
|
link to implementation and configuration details pertaining to that |
|
particular goal.</para> |
|
|
|
<section id="testing-ctx-management"> |
|
<title>Context management and caching</title> |
|
|
|
<para>The Spring TestContext Framework provides consistent loading of |
|
Spring <classname>ApplicationContext</classname>s and caching of those |
|
contexts. Support for the caching of loaded contexts is important, |
|
because if you are working on a large project, startup time may become |
|
an issue - not because of the overhead of Spring itself, but because |
|
the objects instantiated by the Spring container will themselves take |
|
time to instantiate. For example, a project with 50-100 Hibernate |
|
mapping files might take 10-20 seconds to load the mapping files, and |
|
incurring that cost before running every single test in every single |
|
test fixture will lead to slower overall test runs that could reduce |
|
productivity.</para> |
|
|
|
<para>Test classes provide an array containing the resource locations |
|
of XML configuration metadata - typically on the classpath - used to |
|
configure the application. This will be the same, or nearly the same, |
|
as the list of configuration locations specified in |
|
<literal>web.xml</literal> or other deployment configuration.</para> |
|
|
|
<para>By default, once loaded, the configured |
|
<interfacename>ApplicationContext</interfacename> will be reused for |
|
each test. Thus the setup cost will be incurred only once (per test |
|
fixture), and subsequent test execution will be much faster. In the |
|
unlikely case that a test may 'dirty' the application context, |
|
requiring reloading - for example, by changing a bean definition or |
|
the state of an application object - Spring's testing support provides |
|
a mechanism to cause the test fixture to reload the configurations and |
|
rebuild the application context before executing the next test.</para> |
|
|
|
<para>See: context management and caching with the <link |
|
linkend="testcontext-ctx-management">TestContext |
|
Framework</link>.</para> |
|
</section> |
|
|
|
<section id="testing-fixture-di"> |
|
<title>Dependency Injection of test fixtures</title> |
|
|
|
<para>When the TestContext framework loads your application context, |
|
it can optionally configure instances of your test classes via |
|
Dependency Injection. This provides a convenient mechanism for setting |
|
up test fixtures using pre-configured beans from your application |
|
context. A strong benefit here is that you can reuse application |
|
contexts across various testing scenarios (e.g., for configuring |
|
Spring-managed object graphs, transactional proxies, |
|
<classname>DataSource</classname>s, etc.), thus avoiding the need to |
|
duplicate complex test fixture set up for individual test |
|
cases.</para> |
|
|
|
<para>As an example, consider the scenario where we have a class, |
|
<classname>HibernateTitleDao</classname>, that performs data access |
|
logic for say, the <classname>Title</classname> domain object. We want |
|
to write integration tests that test all of the following |
|
areas:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>The Spring configuration: basically, is everything related |
|
to the configuration of the |
|
<classname>HibernateTitleDao</classname> bean correct and |
|
present?</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>The Hibernate mapping file configuration: is everything |
|
mapped correctly and are the correct lazy-loading settings in |
|
place?</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>The logic of the <classname>HibernateTitleDao</classname>: |
|
does the configured instance of this class perform as |
|
anticipated?</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>See: dependency injection of test fixtures with the <link |
|
linkend="testcontext-fixture-di">TestContext Framework</link>.</para> |
|
</section> |
|
|
|
<section id="testing-tx"> |
|
<title>Transaction management</title> |
|
|
|
<para>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.</para> |
|
|
|
<para>The TestContext framework addresses this issue. By default, the |
|
framework will create and roll back a transaction for each test. You |
|
simply write code that can assume the existence of a transaction. If |
|
you call transactionally proxied objects in your tests, they will |
|
behave correctly, according to their transactional semantics. In |
|
addition, if test methods delete the contents of selected tables while |
|
running within a transaction, the transaction will roll back by |
|
default, and the database will return to its state prior to execution |
|
of the test. Transactional support is provided to your test class via |
|
a <classname>PlatformTransactionManager</classname> bean defined in |
|
the test's application context.</para> |
|
|
|
<para>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 |
|
transaction to commit instead of roll back via the <link |
|
linkend="integration-testing-annotations"><interfacename>@TransactionConfiguration</interfacename></link> |
|
and <link |
|
linkend="integration-testing-annotations"><interfacename>@Rollback</interfacename></link> |
|
annotations.</para> |
|
|
|
<para>See: transaction management with the <link |
|
linkend="testcontext-tx">TestContext Framework</link>.</para> |
|
</section> |
|
|
|
<section id="testing-support-classes"> |
|
<title>Integration testing support classes</title> |
|
|
|
<para>The Spring TestContext Framework provides several |
|
<literal>abstract</literal> support classes that can simplify writing |
|
integration tests. These base test classes provide well defined hooks |
|
into the testing framework as well as convenient instance variables |
|
and methods, allowing access to such things as:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>The <literal>ApplicationContext</literal>: useful for |
|
performing explicit bean lookups or testing the state of the |
|
context as a whole.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>A <classname>SimpleJdbcTemplate</classname>: useful for |
|
querying to confirm state. For example, you might query before and |
|
after testing application code that creates an object and persists |
|
it using an ORM tool, to verify that the data appears in the |
|
database. (Spring will ensure that the query runs in the scope of |
|
the same transaction.) You will need to tell your ORM tool to |
|
'flush' its changes for this to work correctly, for example using |
|
the <methodname>flush()</methodname> method on Hibernate's |
|
<interfacename>Session</interfacename> interface.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>In addition, you may find it desirable to provide your own |
|
custom, application-wide superclass for integration tests that |
|
provides further useful instance variables and methods specific to |
|
your project.</para> |
|
|
|
<para>See: support classes for the <link |
|
linkend="testcontext-support-classes">TestContext |
|
Framework</link>.</para> |
|
</section> |
|
</section> |
|
|
|
<section id="integration-testing-support-jdbc"> |
|
<title>JDBC testing support</title> |
|
|
|
<para>The <literal>org.springframework.test.jdbc</literal> package |
|
contains <classname>SimpleJdbcTestUtils</classname>, which is a |
|
Java-5-based collection of JDBC related utility functions intended to |
|
simplify standard database testing scenarios. <emphasis>Note that <link |
|
linkend="testcontext-support-classes-junit38"><classname>AbstractTransactionalJUnit38SpringContextTests</classname></link>, |
|
<link |
|
linkend="testcontext-support-classes-junit4"><classname>AbstractTransactionalJUnit4SpringContextTests</classname></link>, |
|
and <link |
|
linkend="testcontext-support-classes-testng"><classname>AbstractTransactionalTestNGSpringContextTests</classname></link> |
|
provide convenience methods which delegate to |
|
<classname>SimpleJdbcTestUtils</classname> internally.</emphasis></para> |
|
</section> |
|
|
|
<section id="integration-testing-annotations"> |
|
<title>Annotations</title> |
|
|
|
<!-- =============================================================== --> |
|
|
|
<para>The Spring Framework provides the following set of |
|
<emphasis>Spring-specific</emphasis> annotations that you can use in |
|
your unit and integration tests in conjunction with the TestContext |
|
framework. Refer to the respective JavaDoc for further information, |
|
including default attribute values, attribute aliases, etc.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@ContextConfiguration</interfacename></emphasis></para> |
|
|
|
<para>Defines class-level metadata which is used to determine how to |
|
load and configure an |
|
<interfacename>ApplicationContext</interfacename>. Specifically, |
|
<interfacename>@ContextConfiguration</interfacename> defines the |
|
application context resource <literal>locations</literal> to |
|
load as well as the <interfacename>ContextLoader</interfacename> |
|
strategy to use for loading the context.</para> |
|
|
|
<programlisting language="java">@ContextConfiguration(locations={"example/test-context.xml"}, loader=CustomContextLoader.class) |
|
public class CustomConfiguredApplicationContextTests { |
|
<lineannotation>// class body...</lineannotation> |
|
}</programlisting> |
|
|
|
<para>Note: <interfacename>@ContextConfiguration</interfacename> |
|
provides support for <emphasis>inherited</emphasis> resource |
|
locations by default. See the <link |
|
linkend="testcontext-ctx-management">Context management and |
|
caching</link> section and JavaDoc for an example and further |
|
details.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@DirtiesContext</interfacename></emphasis></para> |
|
|
|
<para>Indicates that the underlying Spring |
|
<interfacename>ApplicationContext</interfacename> has been |
|
<emphasis>dirtied</emphasis> during the execution of a test and |
|
should be closed (regardless of whether the test passed or not):</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>after the current test class, when declared on a |
|
class with class mode set to <literal>AFTER_CLASS</literal>, |
|
which is the default class mode</para> |
|
</listitem> |
|
<listitem> |
|
<para>after each test method in the current test class, |
|
when declared on a class with class mode set to |
|
<literal>AFTER_EACH_TEST_METHOD</literal></para> |
|
</listitem> |
|
<listitem> |
|
<para>after the current test, when declared on a method</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>Use this annotation if a test has modified the context |
|
(for example, by replacing a bean definition). Subsequent tests |
|
will be supplied a new context.</para> |
|
|
|
<para><interfacename>@DirtiesContext</interfacename> may be used |
|
as a class-level and method-level annotation within the same class. |
|
In such scenarios, the <interfacename>ApplicationContext</interfacename> |
|
will be marked as <emphasis>dirty</emphasis> after any such |
|
annotated method as well as after the entire class. If the |
|
<classname>ClassMode</classname> is set to |
|
<literal>AFTER_EACH_TEST_METHOD</literal>, the context will be |
|
marked dirty after each test method in the class.</para> |
|
|
|
<programlisting language="java">@DirtiesContext |
|
public class ContextDirtyingTests { |
|
<lineannotation>// some tests that result in the Spring container being dirtied</lineannotation> |
|
}</programlisting> |
|
|
|
<programlisting language="java">@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) |
|
public class ContextDirtyingTests { |
|
<lineannotation>// some tests that result in the Spring container being dirtied</lineannotation> |
|
}</programlisting> |
|
|
|
<programlisting language="java">@DirtiesContext |
|
@Test |
|
public void testProcessWhichDirtiesAppCtx() { |
|
<lineannotation>// some logic that results in the Spring container being dirtied</lineannotation> |
|
}</programlisting> |
|
|
|
<para>Whenever an application context is marked as |
|
<emphasis>dirty</emphasis>, it will be removed from the testing |
|
framework's cache and closed; thus the underlying Spring container will be |
|
rebuilt for any subsequent test which requires a context with the |
|
same set of resource locations.</para> |
|
|
|
<note> |
|
<title>Limitations of <interfacename>@DirtiesContext</interfacename> with JUnit 3.8</title> |
|
<para>In a JUnit 3.8 environment <interfacename>@DirtiesContext</interfacename> |
|
is only supported on methods and thus not at the class level.</para> |
|
</note> |
|
|
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@TestExecutionListeners</interfacename></emphasis></para> |
|
|
|
<para>Defines class-level metadata for configuring which |
|
<interfacename>TestExecutionListener</interfacename>s should be |
|
registered with a <classname>TestContextManager</classname>. |
|
Typically, <interfacename>@TestExecutionListeners</interfacename> |
|
will be used in conjunction with |
|
<interfacename>@ContextConfiguration</interfacename>.</para> |
|
|
|
<programlisting language="java">@ContextConfiguration |
|
@TestExecutionListeners({CustomTestExecutionListener.class, AnotherTestExecutionListener.class}) |
|
public class CustomTestExecutionListenerTests { |
|
<lineannotation>// class body...</lineannotation> |
|
}</programlisting> |
|
|
|
<para>Note: <interfacename>@TestExecutionListeners</interfacename> |
|
provides support for <emphasis>inherited</emphasis> listeners by |
|
default. See the JavaDoc for an example and further details.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@TransactionConfiguration</interfacename></emphasis></para> |
|
|
|
<para>Defines class-level metadata for configuring transactional |
|
tests. Specifically, the bean name of the |
|
<interfacename>PlatformTransactionManager</interfacename> 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, the |
|
<literal>defaultRollback</literal> flag can optionally be changed to |
|
<literal>false</literal>. Typically, |
|
<interfacename>@TransactionConfiguration</interfacename> will be |
|
used in conjunction with |
|
<interfacename>@ContextConfiguration</interfacename>.</para> |
|
|
|
<programlisting language="java">@ContextConfiguration |
|
@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false) |
|
public class CustomConfiguredTransactionalTests { |
|
<lineannotation>// class body...</lineannotation> |
|
}</programlisting> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@Rollback</interfacename></emphasis></para> |
|
|
|
<para>Indicates whether or not the transaction for the annotated |
|
test method should be <emphasis>rolled back</emphasis> after the |
|
test method has completed. If <literal>true</literal>, the |
|
transaction will be rolled back; otherwise, the transaction will be |
|
committed. Use <interfacename>@Rollback</interfacename> to override |
|
the default rollback flag configured at the class level.</para> |
|
|
|
<programlisting language="java">@Rollback(false) |
|
@Test |
|
public void testProcessWithoutRollback() { |
|
<lineannotation>// ...</lineannotation> |
|
}</programlisting> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@BeforeTransaction</interfacename></emphasis></para> |
|
|
|
<para>Indicates that the annotated <literal>public void</literal> |
|
method should be executed <emphasis>before</emphasis> a transaction |
|
is started for test methods configured to run within a transaction |
|
via the <interfacename>@Transactional</interfacename> |
|
annotation.</para> |
|
|
|
<programlisting language="java">@BeforeTransaction |
|
public void beforeTransaction() { |
|
<lineannotation>// logic to be executed before a transaction is started</lineannotation> |
|
}</programlisting> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@AfterTransaction</interfacename></emphasis></para> |
|
|
|
<para>Indicates that the annotated <literal>public void</literal> |
|
method should be executed <emphasis>after</emphasis> a transaction |
|
has been ended for test methods configured to run within a |
|
transaction via the <interfacename>@Transactional</interfacename> |
|
annotation.</para> |
|
|
|
<programlisting language="java">@AfterTransaction |
|
public void afterTransaction() { |
|
<lineannotation>// logic to be executed after a transaction has ended</lineannotation> |
|
}</programlisting> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@NotTransactional</interfacename></emphasis></para> |
|
|
|
<para>The presence of this annotation indicates that the annotated |
|
test method must <emphasis>not</emphasis> execute in a transactional |
|
context.</para> |
|
|
|
<programlisting language="java">@NotTransactional |
|
@Test |
|
public void testProcessWithoutTransaction() { |
|
<lineannotation>// ...</lineannotation> |
|
}</programlisting> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<!-- =============================================================== --> |
|
|
|
<para>The following annotations are <emphasis>only</emphasis> supported |
|
when used in conjunction with JUnit (i.e., with the <link |
|
linkend="testcontext-junit4-runner">SpringJUnit4ClassRunner</link> or |
|
the <link linkend="testcontext-support-classes-junit38">JUnit 3.8</link> |
|
and <link linkend="testcontext-support-classes-junit4">JUnit 4.7</link> |
|
support classes.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@IfProfileValue</interfacename></emphasis></para> |
|
|
|
<para>Indicates that the annotated test is enabled for a specific |
|
testing environment. If the configured |
|
<classname>ProfileValueSource</classname> returns a matching |
|
<literal>value</literal> for the provided <literal>name</literal>, |
|
the test will be enabled. This annotation can be applied to an |
|
entire class or individual methods. Class-level usage overrides |
|
method-level usage.</para> |
|
|
|
<programlisting language="java">@IfProfileValue(name="java.vendor", value="Sun Microsystems Inc.") |
|
@Test |
|
public void testProcessWhichRunsOnlyOnSunJvm() { |
|
<lineannotation>// some logic that should run only on Java VMs from Sun Microsystems</lineannotation> |
|
}</programlisting> |
|
|
|
<para>Alternatively <interfacename>@IfProfileValue</interfacename> |
|
may be configured with a list of <literal>values</literal> (with |
|
<emphasis>OR</emphasis> semantics) to achieve TestNG-like support |
|
for <emphasis>test groups</emphasis> in a JUnit environment. |
|
Consider the following example:</para> |
|
|
|
<programlisting language="java">@IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"}) |
|
@Test |
|
public void testProcessWhichRunsForUnitOrIntegrationTestGroups() { |
|
<lineannotation>// some logic that should run only for unit and integration test groups</lineannotation> |
|
}</programlisting> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@ProfileValueSourceConfiguration</interfacename></emphasis></para> |
|
|
|
<para>Class-level annotation which is used to specify what type of |
|
<literal>ProfileValueSource</literal> to use when retrieving |
|
<emphasis>profile values</emphasis> configured via the |
|
<interfacename>@IfProfileValue</interfacename> annotation. If |
|
<interfacename>@ProfileValueSourceConfiguration</interfacename> is |
|
not declared for a test, |
|
<classname>SystemProfileValueSource</classname> will be used by |
|
default.</para> |
|
|
|
<programlisting language="java">@ProfileValueSourceConfiguration(CustomProfileValueSource.class) |
|
public class CustomProfileValueSourceTests { |
|
<lineannotation>// class body...</lineannotation> |
|
}</programlisting> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@ExpectedException</interfacename></emphasis></para> |
|
|
|
<para>Indicates that the annotated test method is expected to throw |
|
an exception during execution. The type of the expected exception is |
|
provided in the annotation, and if an instance of the exception is |
|
thrown during the test method execution then the test passes. |
|
Likewise if an instance of the exception is <emphasis>not</emphasis> |
|
thrown during the test method execution then the test fails.</para> |
|
|
|
<programlisting language="java">@ExpectedException(SomeBusinessException.class) |
|
public void testProcessRainyDayScenario() { |
|
<lineannotation>// some logic that should result in an <classname>Exception</classname> being thrown</lineannotation> |
|
}</programlisting> |
|
|
|
<para>Using Spring's |
|
<interfacename>@ExpectedException</interfacename> annotation in |
|
conjunction with JUnit 4's |
|
<interfacename>@Test(expected=...)</interfacename> configuration |
|
would lead to an unresolvable conflict. Developers must therefore |
|
choose one or the other when integrating with JUnit 4, in which case |
|
it is generally preferable to use the explicit JUnit 4 |
|
configuration.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@Timed</interfacename></emphasis></para> |
|
|
|
<para>Indicates that the annotated test method has to finish |
|
execution in a specified time period (in milliseconds). If the text |
|
execution time takes longer than the specified time period, the test |
|
fails.</para> |
|
|
|
<para>Note that the time period includes execution of the test |
|
method itself, any repetitions of the test (see |
|
<interfacename>@Repeat</interfacename>), as well as any |
|
<emphasis>set up</emphasis> or <emphasis>tear down</emphasis> of the |
|
test fixture.</para> |
|
|
|
<programlisting language="java">@Timed(millis=1000) |
|
public void testProcessWithOneSecondTimeout() { |
|
<lineannotation>// some logic that should not take longer than 1 second to execute</lineannotation> |
|
}</programlisting> |
|
|
|
<para>Spring's <interfacename>@Timed</interfacename> annotation has |
|
different semantics than JUnit 4's |
|
<interfacename>@Test(timeout=...)</interfacename> support. |
|
Specifically, due to the manner in which JUnit 4 handles test |
|
execution timeouts (i.e., by executing the test method in a separate |
|
<classname>Thread</classname>), |
|
<interfacename>@Test(timeout=...)</interfacename> applies to |
|
<emphasis>each iteration</emphasis> in the case of repetitions and |
|
preemptively fails the test if the test takes too long. Spring's |
|
<interfacename>@Timed</interfacename>, on the other hand, times the |
|
<emphasis>total</emphasis> test execution time (including all |
|
repetitions) and does not preemptively fail the test but rather |
|
waits for the test to actually complete before failing.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@Repeat</interfacename></emphasis></para> |
|
|
|
<para>Indicates that the annotated test method must be executed |
|
repeatedly. The number of times that the test method is to be |
|
executed is specified in the annotation.</para> |
|
|
|
<para>Note that the scope of execution to be repeated includes |
|
execution of the test method itself as well as any <emphasis>set |
|
up</emphasis> or <emphasis>tear down</emphasis> of the test |
|
fixture.</para> |
|
|
|
<programlisting language="java">@Repeat(10) |
|
@Test |
|
public void testProcessRepeatedly() { |
|
<lineannotation>// ...</lineannotation> |
|
}</programlisting> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<!-- =============================================================== --> |
|
|
|
<para>The following non-test-specific annotations are supported with |
|
standard semantics for all configurations of the Spring TestContext |
|
Framework.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@Autowired</interfacename></emphasis></para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@Qualifier</interfacename></emphasis></para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@Resource</interfacename></emphasis> |
|
(javax.annotation) <emphasis>if JSR-250 is present</emphasis></para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@PersistenceContext</interfacename></emphasis> |
|
(javax.persistence) <emphasis>if JPA is present</emphasis></para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@PersistenceUnit</interfacename></emphasis> |
|
(javax.persistence) <emphasis>if JPA is present</emphasis></para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@Required</interfacename></emphasis></para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><emphasis |
|
role="bold"><interfacename>@Transactional</interfacename></emphasis></para> |
|
</listitem> |
|
</itemizedlist> |
|
</section> |
|
|
|
<section id="testcontext-framework"> |
|
<title>Spring TestContext Framework</title> |
|
|
|
<para>The <emphasis>Spring <classname>TestContext</classname> |
|
Framework</emphasis> (located in the |
|
<literal>org.springframework.test.context</literal> package) provides |
|
generic, annotation-driven unit and integration testing support that |
|
is agnostic of the testing framework in use, for example JUnit 3.8, |
|
JUnit 4.7, TestNG 5.10, etc. The TestContext framework also places a |
|
great deal of importance on <emphasis>convention over |
|
configuration</emphasis> with reasonable defaults that can be |
|
overridden via annotation-based configuration.</para> |
|
|
|
<para>In addition to generic testing infrastructure, the TestContext |
|
framework provides explicit support for JUnit 3.8, JUnit 4.7, and |
|
TestNG 5.10 in the form of <literal>abstract</literal> support |
|
classes. For JUnit 4.7, the framework also provides a custom |
|
<interfacename>Runner</interfacename> which allows one to write test |
|
classes that are not required to extend a particular class |
|
hierarchy.</para> |
|
|
|
<para>The following section provides an overview of the internals of the |
|
TestContext framework. If you are only interested in using the framework |
|
and not necessarily interested in extending it with your own custom |
|
listeners, feel free to go directly to the configuration (<link |
|
linkend="testcontext-ctx-management">context management</link>, <link |
|
linkend="testcontext-fixture-di">dependency injection</link>, <link |
|
linkend="testcontext-tx">transaction management</link>), <link |
|
linkend="testcontext-support-classes">support classes</link>, and <link |
|
linkend="integration-testing-annotations">annotation support</link> |
|
sections.</para> |
|
|
|
<!-- ================================================================= --> |
|
|
|
<section id="testcontext-key-abstractions"> |
|
<title>Key abstractions</title> |
|
|
|
<para>The core of the framework consists of the |
|
<classname>TestContext</classname> and |
|
<classname>TestContextManager</classname> classes and the |
|
<interfacename>TestExecutionListener</interfacename> interface. A |
|
<classname>TestContextManager</classname> is created on a per-test |
|
basis. The <classname>TestContextManager</classname> in turn manages a |
|
<classname>TestContext</classname> which is responsible for holding |
|
the context of the current test. The |
|
<classname>TestContextManager</classname> is also responsible for |
|
updating the state of the <classname>TestContext</classname> as the |
|
test progresses and delegating to |
|
<interfacename>TestExecutionListener</interfacename>s, which |
|
instrument the actual test execution (e.g., providing dependency |
|
injection, managing transactions, etc.). Consult the JavaDoc and the |
|
Spring test suite for further information and examples of various |
|
configurations.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><classname>TestContext</classname>: encapsulates the context |
|
in which a test is executed, agnostic of the actual testing |
|
framework in use.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><classname>TestContextManager</classname>: the main entry |
|
point into the <emphasis>Spring TestContext Framework</emphasis>, |
|
which is responsible for managing a single |
|
<classname>TestContext</classname> and signaling events to all |
|
registered <interfacename>TestExecutionListener</interfacename>s |
|
at well defined test execution points: test instance preparation, |
|
prior to any <emphasis>before methods</emphasis> of a particular |
|
testing framework, and after any <emphasis>after |
|
methods</emphasis> of a particular testing framework.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><interfacename>TestExecutionListener</interfacename>: |
|
defines a <emphasis>listener</emphasis> API for reacting to test |
|
execution events published by the |
|
<classname>TestContextManager</classname> with which the listener |
|
is registered.</para> |
|
|
|
<para>Spring provides three |
|
<interfacename>TestExecutionListener</interfacename> |
|
implementations which are configured by default: |
|
<classname>DependencyInjectionTestExecutionListener</classname>, |
|
<classname>DirtiesContextTestExecutionListener</classname>, and |
|
<classname>TransactionalTestExecutionListener</classname>, which |
|
provide support for dependency injection of the test instance, |
|
handling of the <interfacename>@DirtiesContext</interfacename> |
|
annotation, and transactional test execution support with default |
|
rollback semantics, respectively.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>The following three sections explain how to configure the |
|
<classname>TestContext</classname> framework via annotations and |
|
provide working examples of how to actually write unit and integration |
|
tests with the framework.</para> |
|
</section> |
|
|
|
<!-- ================================================================= --> |
|
|
|
<section id="testcontext-ctx-management"> |
|
<title>Context management and caching</title> |
|
|
|
<para>Each <classname>TestContext</classname> provides context |
|
management and caching support for the test instance for which it is |
|
responsible. Test instances do not automatically receive access to the |
|
configured <classname>ApplicationContext</classname>; however, if a |
|
test class implements the |
|
<interfacename>ApplicationContextAware</interfacename> interface, a |
|
reference to the <classname>ApplicationContext</classname> will be |
|
supplied to the test instance (provided the |
|
<classname>DependencyInjectionTestExecutionListener</classname> has |
|
been configured, which is the default). Note that |
|
<classname>AbstractJUnit38SpringContextTests</classname>, |
|
<classname>AbstractJUnit4SpringContextTests</classname>, and |
|
<classname>AbstractTestNGSpringContextTests</classname> already |
|
implement <interfacename>ApplicationContextAware</interfacename> and |
|
therefore provide this functionality out-of-the-box.</para> |
|
|
|
<tip> |
|
<title>@Autowired ApplicationContext</title> |
|
|
|
<para>As an alternative to implementing the |
|
<interfacename>ApplicationContextAware</interfacename> interface, |
|
your test class can have its application context injected via the |
|
<interfacename>@Autowired</interfacename> annotation on either a |
|
field or setter method, for example:</para> |
|
|
|
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
|
@ContextConfiguration |
|
public class MyTest { |
|
|
|
<emphasis role="bold">@Autowired</emphasis> |
|
private ApplicationContext applicationContext; |
|
|
|
<lineannotation>// class body...</lineannotation> |
|
}</programlisting> |
|
</tip> |
|
|
|
<para>In contrast to the now deprecated JUnit 3.8 legacy class |
|
hierarchy, test classes which use the TestContext framework do not |
|
need to override any <literal>protected</literal> instance methods to |
|
configure their application context. Rather, configuration is achieved |
|
merely by declaring the |
|
<interfacename>@ContextConfiguration</interfacename> annotation at the |
|
class level. If your test class does not explicitly declare any |
|
application context resource <literal>locations</literal>, the |
|
configured <interfacename>ContextLoader</interfacename> will determine |
|
how and whether or not to load a context from a default set of |
|
locations. For example, <classname>GenericXmlContextLoader</classname> |
|
- which is the default <interfacename>ContextLoader</interfacename> - |
|
will generate a default location based on the name of the test class. |
|
If your class is named <literal>com.example.MyTest</literal>, |
|
<classname>GenericXmlContextLoader</classname> will load your |
|
application context from |
|
<literal>"classpath:/com/example/MyTest-context.xml"</literal>.</para> |
|
|
|
<programlisting language="java">package com.example; |
|
|
|
@RunWith(SpringJUnit4ClassRunner.class) |
|
<lineannotation>// ApplicationContext will be loaded from <literal>"classpath:/com/example/MyTest-context.xml"</literal></lineannotation> |
|
<emphasis role="bold">@ContextConfiguration</emphasis> |
|
public class MyTest { |
|
<lineannotation>// class body...</lineannotation> |
|
}</programlisting> |
|
|
|
<para>If the default location does not suit your needs, you are free |
|
to explicitly configure the <literal>locations</literal> attribute of |
|
<interfacename>@ContextConfiguration</interfacename> (see code listing |
|
below) with an array containing the resource locations of XML |
|
configuration metadata (assuming an XML-capable |
|
<interfacename>ContextLoader</interfacename> has been configured) - |
|
typically on the classpath - used to configure the application. This |
|
will be the same, or nearly the same, as the list of configuration |
|
locations specified in <literal>web.xml</literal> or other deployment |
|
configuration. As an alternative you may choose to implement and |
|
configure your own custom |
|
<interfacename>ContextLoader</interfacename>.</para> |
|
|
|
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
|
<lineannotation>// ApplicationContext will be loaded from <literal>"/applicationContext.xml"</literal> and <literal>"/applicationContext-test.xml"</literal></lineannotation> |
|
<lineannotation>// in the root of the classpath</lineannotation> |
|
<emphasis role="bold">@ContextConfiguration({"/applicationContext.xml", "/applicationContext-test.xml"})</emphasis> |
|
public class MyTest { |
|
<lineannotation>// class body...</lineannotation> |
|
}</programlisting> |
|
|
|
<para><interfacename>@ContextConfiguration</interfacename> supports an |
|
alias for the <literal>locations</literal> attribute via the standard |
|
<literal>value</literal> attribute. Thus, if you do not need to |
|
configure a custom <interfacename>ContextLoader</interfacename>, you |
|
can omit the declaration of the <literal>locations</literal> attribute |
|
name and declare the resource locations using the shorthand format |
|
demonstrated in the following example. |
|
<interfacename>@ContextConfiguration</interfacename> also supports a |
|
boolean <literal>inheritLocations</literal> attribute which denotes |
|
whether or not resource locations from superclasses should be |
|
<emphasis>inherited</emphasis>. The default value is |
|
<literal>true</literal>, which means that an annotated class will |
|
<emphasis>inherit</emphasis> the resource locations defined by an |
|
annotated superclass. Specifically, the resource locations for an |
|
annotated class will be appended to the list of resource locations |
|
defined by an annotated superclass. Thus, subclasses have the option |
|
of <emphasis>extending</emphasis> the list of resource locations. In |
|
the following example, the |
|
<interfacename>ApplicationContext</interfacename> for |
|
<classname>ExtendedTest</classname> will be loaded from |
|
"/base-context.xml" <emphasis role="bold">and</emphasis> |
|
"/extended-context.xml", in that order. Beans defined in |
|
"/extended-context.xml" may therefore override those defined in |
|
"/base-context.xml".</para> |
|
|
|
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
|
<lineannotation>// ApplicationContext will be loaded from <literal>"/base-context.xml"</literal> in the root of the classpath</lineannotation> |
|
<emphasis role="bold">@ContextConfiguration("/base-context.xml")</emphasis> |
|
public class BaseTest { |
|
<lineannotation>// class body...</lineannotation> |
|
} |
|
|
|
<lineannotation>// ApplicationContext will be loaded from <literal>"/base-context.xml"</literal> and <literal>"/extended-context.xml"</literal></lineannotation> |
|
<lineannotation>// in the root of the classpath</lineannotation> |
|
<emphasis role="bold">@ContextConfiguration("/extended-context.xml")</emphasis> |
|
public class ExtendedTest extends BaseTest { |
|
<lineannotation>// class body...</lineannotation> |
|
}</programlisting> |
|
|
|
<para>If <literal>inheritLocations</literal> is set to |
|
<literal>false</literal>, the resource locations for the annotated |
|
class will <emphasis>shadow</emphasis> and effectively replace any |
|
resource locations defined by a superclass.</para> |
|
|
|
<para>By default, once loaded, the configured |
|
<interfacename>ApplicationContext</interfacename> will be reused for |
|
each test. Thus the setup cost will be incurred only once (per test |
|
fixture), and subsequent test execution will be much faster. In the |
|
unlikely case that a test may <emphasis>dirty</emphasis> the |
|
application context, requiring reloading - for example, by changing a |
|
bean definition or the state of an application object - you may |
|
annotate your test method with |
|
<interfacename>@DirtiesContext</interfacename> (assuming |
|
<classname>DirtiesContextTestExecutionListener</classname> has been |
|
configured, which is the default) to cause the test fixture to reload |
|
the configurations and rebuild the application context before |
|
executing the next test.</para> |
|
</section> |
|
|
|
<!-- ================================================================= --> |
|
|
|
<section id="testcontext-fixture-di"> |
|
<title>Dependency Injection of test fixtures</title> |
|
|
|
<para>When you configure the |
|
<classname>DependencyInjectionTestExecutionListener</classname> - |
|
which is configured by default - via the |
|
<interfacename>@TestExecutionListeners</interfacename> annotation, the |
|
dependencies of your test instances will be |
|
<emphasis>injected</emphasis> from beans in the application context |
|
you configured via |
|
<interfacename>@ContextConfiguration</interfacename> by Setter |
|
Injection, Field Injection, or both, depending on which annotations |
|
you choose and whether you place them on setter methods or fields. For |
|
consistency with the annotation support introduced in Spring 2.5, you |
|
may choose either Spring's <interfacename>@Autowired</interfacename> |
|
annotation or the <interfacename>@Resource</interfacename> annotation |
|
from JSR 250. The semantics for both are consistent throughout the |
|
Spring Framework. For example, if you prefer <link |
|
linkend="beans-factory-autowire"><emphasis>autowiring by |
|
type</emphasis></link>, annotate your setter methods or fields with |
|
<interfacename>@Autowired</interfacename>. On the other hand, if you |
|
prefer to have your dependencies injected <emphasis>by |
|
name</emphasis>, annotate your setter methods or fields with |
|
<interfacename>@Resource</interfacename>.</para> |
|
|
|
<tip> |
|
<para>The TestContext framework does not instrument the manner in |
|
which a test instance is instantiated. Thus the use of |
|
<interfacename>@Autowired</interfacename> for constructors has no |
|
effect for test classes.</para> |
|
</tip> |
|
|
|
<para>Since <interfacename>@Autowired</interfacename> performs <link |
|
linkend="beans-factory-autowire"><emphasis>autowiring by |
|
type</emphasis></link>, if you have multiple bean definitions of the |
|
same type, you cannot rely on this approach for those particular |
|
beans. In that case, you can use |
|
<interfacename>@Resource</interfacename> for injection <emphasis>by |
|
name</emphasis>. Alternatively, if your test class has access to its |
|
<classname>ApplicationContext</classname>, you can perform an explicit |
|
lookup using (for example) a call to |
|
<methodname>applicationContext.getBean("titleDao")</methodname>. A |
|
third option is to use <interfacename>@Autowired</interfacename> in |
|
conjunction with <interfacename>@Qualifier</interfacename>.</para> |
|
|
|
<para>If you don't want dependency injection applied to your test |
|
instances, simply don't annotate any fields or setter methods with |
|
<interfacename>@Autowired</interfacename> or |
|
<interfacename>@Resource</interfacename>. Alternatively, you can |
|
disable dependency injection altogether by explicitly configuring your |
|
class with <interfacename>@TestExecutionListeners</interfacename> and |
|
omitting |
|
<literal>DependencyInjectionTestExecutionListener.class</literal> from |
|
the list of listeners.</para> |
|
|
|
<para>Consider the scenario where we have a class, |
|
<classname>HibernateTitleDao</classname> (as outlined in the <link |
|
linkend="testing-fixture-di">Goals</link> section). First, let's look |
|
at a JUnit 4.7 based implementation of the test class itself which |
|
uses <interfacename>@Autowired</interfacename> for field injection (we |
|
will look at the application context configuration after all sample |
|
code listings). <emphasis>Note: The dependency injection behavior in |
|
the following code listings is not in any way specific to JUnit 4.7. |
|
The same DI techniques can be used in conjunction with any testing |
|
framework.</emphasis></para> |
|
|
|
<note> |
|
<title>Static imports for assertions</title> |
|
<para>The following examples make calls to static |
|
assertion methods such as <literal>assertNotNull()</literal> |
|
but without prepending the call with |
|
"<literal>Assert.</literal>". In such cases you should assume |
|
that the method has been properly imported via |
|
an <literal>import static</literal> declaration which is |
|
simply not shown in the example.</para> |
|
</note> |
|
|
|
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
|
<lineannotation>// specifies the Spring configuration to load for this test fixture</lineannotation> |
|
<emphasis role="bold">@ContextConfiguration("daos.xml")</emphasis> |
|
public final class HibernateTitleDaoTests { |
|
|
|
<lineannotation>// this instance will be dependency injected <emphasis |
|
role="bold">by type</emphasis></lineannotation> |
|
<emphasis role="bold">@Autowired</emphasis> |
|
private HibernateTitleDao titleDao; |
|
|
|
public void testLoadTitle() throws Exception { |
|
Title title = this.titleDao.loadTitle(new Long(10)); |
|
assertNotNull(title); |
|
} |
|
}</programlisting> |
|
|
|
<!-- =============================================================== --> |
|
|
|
<para>Alternatively, we can configure the class to use |
|
<interfacename>@Autowired</interfacename> for setter injection.</para> |
|
|
|
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
|
<lineannotation>// specifies the Spring configuration to load for this test fixture</lineannotation> |
|
<emphasis role="bold">@ContextConfiguration("daos.xml")</emphasis> |
|
public final class HibernateTitleDaoTests { |
|
|
|
<lineannotation>// this instance will be dependency injected <emphasis |
|
role="bold">by type</emphasis></lineannotation> |
|
private HibernateTitleDao titleDao; |
|
|
|
<emphasis role="bold">@Autowired</emphasis> |
|
public void setTitleDao(HibernateTitleDao titleDao) { |
|
this.titleDao = titleDao; |
|
} |
|
|
|
public void testLoadTitle() throws Exception { |
|
Title title = this.titleDao.loadTitle(new Long(10)); |
|
assertNotNull(title); |
|
} |
|
}</programlisting> |
|
|
|
<!-- =============================================================== --> |
|
|
|
<para>Now let's take a look at an example using |
|
<interfacename>@Resource</interfacename> for field injection.</para> |
|
|
|
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
|
<lineannotation>// specifies the Spring configuration to load for this test fixture</lineannotation> |
|
<emphasis role="bold">@ContextConfiguration("daos.xml")</emphasis> |
|
public final class HibernateTitleDaoTests { |
|
|
|
<lineannotation>// this instance will be dependency injected <emphasis |
|
role="bold">by name</emphasis></lineannotation> |
|
<emphasis role="bold">@Resource</emphasis> |
|
private HibernateTitleDao titleDao; |
|
|
|
public void testLoadTitle() throws Exception { |
|
Title title = this.titleDao.loadTitle(new Long(10)); |
|
assertNotNull(title); |
|
} |
|
}</programlisting> |
|
|
|
<!-- =============================================================== --> |
|
|
|
<para>Finally, here is an example using |
|
<interfacename>@Resource</interfacename> for setter injection.</para> |
|
|
|
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
|
<lineannotation>// specifies the Spring configuration to load for this test fixture</lineannotation> |
|
<emphasis role="bold">@ContextConfiguration("daos.xml")</emphasis> |
|
public final class HibernateTitleDaoTests { |
|
|
|
<lineannotation>// this instance will be dependency injected <emphasis |
|
role="bold">by name</emphasis></lineannotation> |
|
private HibernateTitleDao titleDao; |
|
|
|
<emphasis role="bold">@Resource</emphasis> |
|
public void setTitleDao(HibernateTitleDao titleDao) { |
|
this.titleDao = titleDao; |
|
} |
|
|
|
public void testLoadTitle() throws Exception { |
|
Title title = this.titleDao.loadTitle(new Long(10)); |
|
assertNotNull(title); |
|
} |
|
}</programlisting> |
|
|
|
<!-- =============================================================== --> |
|
|
|
<para>The above code listings use the same XML context file referenced |
|
by the <interfacename>@ContextConfiguration</interfacename> annotation |
|
(i.e., <literal>"daos.xml"</literal>) which looks like this:</para> |
|
|
|
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?> |
|
<beans xmlns="http://www.springframework.org/schema/beans" |
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
xsi:schemaLocation="http://www.springframework.org/schema/beans |
|
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> |
|
|
|
<lineannotation><!-- this bean will be injected into the <classname>HibernateTitleDaoTests</classname> class --></lineannotation> |
|
<bean id="<emphasis role="bold">titleDao</emphasis>" class="<emphasis |
|
role="bold">com.foo.dao.hibernate.HibernateTitleDao</emphasis>"> |
|
<property name="sessionFactory" ref="sessionFactory"/> |
|
</bean> |
|
|
|
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> |
|
<lineannotation><!-- dependencies elided for clarity --></lineannotation> |
|
</bean> |
|
|
|
</beans></programlisting> |
|
|
|
<note> |
|
<para>If you are extending from a Spring-provided test base class |
|
that happens to use <interfacename>@Autowired</interfacename> on one |
|
of its setters methods, you might have multiple beans of the |
|
affected type defined in your application context: e.g. multiple |
|
<interfacename>DataSource</interfacename> beans. In such a case, you |
|
may override the setter and use the |
|
<interfacename>@Qualifier</interfacename> annotation to indicate a |
|
specific target bean as follows:</para> |
|
|
|
<programlisting language="java"><lineannotation>// ...</lineannotation> |
|
|
|
@Autowired |
|
@Override |
|
public void setDataSource(<emphasis role="bold">@Qualifier("myDataSource")</emphasis> DataSource dataSource) { |
|
super.setDataSource(dataSource); |
|
} |
|
|
|
<lineannotation>// ...</lineannotation></programlisting> |
|
|
|
<para>The specified qualifier value indicates the specific |
|
<interfacename>DataSource</interfacename> bean to inject, narrowing |
|
the set of type matches to a specific bean. Its value is matched |
|
against <literal><qualifier></literal> declarations within the |
|
corresponding <literal><bean></literal> definitions. The bean |
|
name is used as a fallback qualifier value, so you may effectively |
|
also point to a specific bean by name there (as shown above, |
|
assuming that "myDataSource" is the bean id). If there is only one |
|
<interfacename>DataSource</interfacename> bean to begin with, then |
|
the qualifier will simply not have any effect - independent from the |
|
bean name of that single matching bean.</para> |
|
|
|
<para>Alternatively, consider using the |
|
<interfacename>@Resource</interfacename> annotation on such an |
|
overridden setter methods, defining the target bean name explicitly |
|
- 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.</para> |
|
|
|
<programlisting language="java"><lineannotation>// ...</lineannotation> |
|
|
|
<emphasis role="bold">@Resource("myDataSource")</emphasis> |
|
@Override |
|
public void setDataSource(DataSource dataSource) { |
|
super.setDataSource(dataSource); |
|
} |
|
|
|
<lineannotation>// ...</lineannotation></programlisting> |
|
</note> |
|
</section> |
|
|
|
<!-- ================================================================= --> |
|
|
|
<section id="testcontext-tx"> |
|
<title>Transaction management</title> |
|
|
|
<para>In the TestContext framework, transactions are managed by the |
|
<classname>TransactionalTestExecutionListener</classname>, which is |
|
configured via the |
|
<interfacename>@TestExecutionListeners</interfacename> annotation by |
|
default, even if you do not explicitly declare |
|
<interfacename>@TestExecutionListeners</interfacename> on your test |
|
class. To enable support for transactions, however, you must provide a |
|
<classname>PlatformTransactionManager</classname> bean in the |
|
application context loaded via |
|
<interfacename>@ContextConfiguration</interfacename> semantics. In |
|
addition, you must declare |
|
<interfacename>@Transactional</interfacename> either at the class or |
|
method level.</para> |
|
|
|
<para>For class-level transaction configuration (i.e., setting the |
|
bean name for the transaction manager and the default rollback flag), |
|
see the <interfacename>@TransactionConfiguration</interfacename> entry |
|
in the <link linkend="integration-testing-annotations">annotation |
|
support</link> section.</para> |
|
|
|
<para>There are several options for configuring transactions for |
|
individual test methods. If transactions are not enabled for the |
|
entire test class, methods may be explicitly annotated with |
|
<interfacename>@Transactional</interfacename>. Similarly, if |
|
transactions <emphasis>are</emphasis> enabled for the entire test |
|
class, methods may be explicitly flagged not to run within a |
|
transaction by annotating them with |
|
<interfacename>@NotTransactional</interfacename>. To control whether |
|
or not a transaction should commit for a particular test method, you |
|
may use the <interfacename>@Rollback</interfacename> annotation to |
|
override the class-level default rollback setting.</para> |
|
|
|
<para><emphasis>Note that <link |
|
linkend="testcontext-support-classes-junit38"><classname>AbstractTransactionalJUnit38SpringContextTests</classname></link>, |
|
<link |
|
linkend="testcontext-support-classes-junit4"><classname>AbstractTransactionalJUnit4SpringContextTests</classname></link>, |
|
and <link |
|
linkend="testcontext-support-classes-testng"><classname>AbstractTransactionalTestNGSpringContextTests</classname></link> |
|
are pre-configured for transactional support at the class level. |
|
</emphasis></para> |
|
|
|
<para>You will occasionally find that you need to execute certain code |
|
before or after a transactional test method but outside the |
|
transactional context, for example to verify the initial database |
|
state prior to execution of your test or to verify expected |
|
transactional commit behavior after test execution (e.g., if the test |
|
was configured not to roll back the transaction). |
|
<classname>TransactionalTestExecutionListener</classname> supports the |
|
<interfacename>@BeforeTransaction</interfacename> and |
|
<interfacename>@AfterTransaction</interfacename> annotations exactly |
|
for such scenarios. Simply annotate any <literal>public void</literal> |
|
method in your test class with one of these annotations, and the |
|
<classname>TransactionalTestExecutionListener</classname> will ensure |
|
that your <emphasis>before transaction method</emphasis> or |
|
<emphasis>after transaction method</emphasis> is executed at the |
|
appropriate time.</para> |
|
|
|
<tip> |
|
<para>Any <emphasis>before methods</emphasis> (e.g., methods |
|
annotated with JUnit 4's @Before) and any <emphasis>after |
|
methods</emphasis> (e.g., methods annotated with JUnit 4's @After) |
|
will be executed <emphasis role="bold">within</emphasis> a |
|
transaction. In addition, methods annotated with |
|
<interfacename>@BeforeTransaction</interfacename> or |
|
<interfacename>@AfterTransaction</interfacename> will naturally not |
|
be executed for tests annotated with |
|
<interfacename>@NotTransactional</interfacename>.</para> |
|
</tip> |
|
|
|
<para>The following JUnit 4 based example displays a fictitious |
|
integration testing scenario highlighting several of the |
|
transaction-related annotations. Consult the <link |
|
linkend="integration-testing-annotations">annotation support</link> |
|
section of the reference manual for further information and |
|
configuration examples.</para> |
|
|
|
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
|
@ContextConfiguration |
|
<emphasis role="bold">@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)</emphasis> |
|
<emphasis role="bold">@Transactional</emphasis> |
|
public class FictitiousTransactionalTest { |
|
|
|
<emphasis role="bold">@BeforeTransaction</emphasis> |
|
public void verifyInitialDatabaseState() { |
|
<lineannotation>// logic to verify the initial state before a transaction is started</lineannotation> |
|
} |
|
|
|
@Before |
|
public void setUpTestDataWithinTransaction() { |
|
<lineannotation>// set up test data within the transaction</lineannotation> |
|
} |
|
|
|
@Test |
|
<lineannotation>// overrides the class-level defaultRollback setting</lineannotation> |
|
<emphasis role="bold">@Rollback(true)</emphasis> |
|
public void modifyDatabaseWithinTransaction() { |
|
<lineannotation>// logic which uses the test data and modifies database state</lineannotation> |
|
} |
|
|
|
@After |
|
public void tearDownWithinTransaction() { |
|
<lineannotation>// execute "tear down" logic within the transaction</lineannotation> |
|
} |
|
|
|
<emphasis role="bold">@AfterTransaction</emphasis> |
|
public void verifyFinalDatabaseState() { |
|
<lineannotation>// logic to verify the final state after transaction has rolled back</lineannotation> |
|
} |
|
|
|
@Test |
|
<emphasis role="bold">@NotTransactional</emphasis> |
|
public void performNonDatabaseRelatedAction() { |
|
<lineannotation>// logic which does not modify database state</lineannotation> |
|
} |
|
}</programlisting> |
|
|
|
<note> |
|
<title>Avoid false positives when testing ORM code</title> |
|
<para>When testing code involving an ORM framework such as JPA |
|
or Hibernate, it is a good practice to |
|
<emphasis>flush</emphasis> the underlying session within test |
|
methods which update the state of the session. Failing to flush |
|
the ORM framework's underlying session can lead to |
|
<emphasis>false positives</emphasis>: your test may pass, but |
|
the same code will throw an exception in a live, production |
|
environment. In the following Hibernate-based example test case, |
|
we have two methods: one which demonstrates a false positive |
|
and one which correctly exposes the results of flushing the |
|
session.</para> |
|
|
|
<programlisting language="java"><lineannotation>// ...</lineannotation> |
|
|
|
@Autowired |
|
private SessionFactory sessionFactory; |
|
|
|
@Test // no expected exception! |
|
public void falsePositive() { |
|
updateEntityInHibernateSession(); |
|
// False positive: an exception will be thrown once the session is |
|
// finally flushed (i.e., in production code) |
|
} |
|
|
|
@Test(expected = GenericJDBCException.class) |
|
public void updateWithSessionFlush() { |
|
updateEntityInHibernateSession(); |
|
// Manual flush is required to avoid false positive in test |
|
sessionFactory.getCurrentSession().flush(); |
|
} |
|
|
|
<lineannotation>// ...</lineannotation></programlisting> |
|
</note> |
|
|
|
</section> |
|
|
|
<!-- ================================================================= --> |
|
|
|
<section id="testcontext-support-classes"> |
|
<title>TestContext support classes</title> |
|
|
|
<section id="testcontext-support-classes-junit38"> |
|
<title>JUnit 3.8 support classes</title> |
|
|
|
<para>The |
|
<literal>org.springframework.test.context.junit38</literal> package |
|
provides support classes for JUnit 3.8 based test cases.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><classname>AbstractJUnit38SpringContextTests</classname>:</para> |
|
|
|
<para>Abstract <classname>TestCase</classname> which integrates |
|
the <emphasis>Spring TestContext Framework</emphasis> with |
|
explicit <classname>ApplicationContext</classname> testing |
|
support in a JUnit 3.8 environment. When you extend the |
|
<classname>AbstractJUnit38SpringContextTests</classname> class |
|
you will have access to the following |
|
<literal>protected</literal> instance variables:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>applicationContext</literal>: use this to |
|
perform explicit bean lookups or to test the state of the |
|
context as a whole.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><classname>AbstractTransactionalJUnit38SpringContextTests</classname>:</para> |
|
|
|
<para>Abstract <emphasis>transactional</emphasis> extension of |
|
<classname>AbstractJUnit38SpringContextTests</classname> that |
|
also adds some convenience functionality for JDBC access. |
|
Expects a <classname>javax.sql.DataSource</classname> bean and a |
|
<interfacename>PlatformTransactionManager</interfacename> bean |
|
to be defined in the <classname>ApplicationContext</classname>. |
|
When you extend the |
|
<classname>AbstractTransactionalJUnit38SpringContextTests</classname> |
|
class you will have access to the following |
|
<literal>protected</literal> instance variables:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>applicationContext</literal>: inherited from |
|
the <classname>AbstractJUnit38SpringContextTests</classname> |
|
superclass. Use this to perform explicit bean lookups or to |
|
test the state of the context as a whole.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>simpleJdbcTemplate</literal>: useful for |
|
querying to confirm state. For example, you might query |
|
before and after testing application code that creates an |
|
object and persists it using an ORM tool, to verify that the |
|
data appears in the database. (Spring will ensure that the |
|
query runs in the scope of the same transaction.) You will |
|
need to tell your ORM tool to 'flush' its changes for this |
|
to work correctly, for example using the |
|
<methodname>flush()</methodname> method on Hibernate's |
|
<classname>Session</classname> interface.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</listitem> |
|
</itemizedlist> |
|
</section> |
|
|
|
<section id="testcontext-support-classes-junit4"> |
|
<title>JUnit 4.7 support classes</title> |
|
|
|
<para>The <literal>org.springframework.test.context.junit4</literal> |
|
package provides support classes for JUnit 4.7 based test |
|
cases.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><classname>AbstractJUnit4SpringContextTests</classname>:</para> |
|
|
|
<para>Abstract base test class which integrates the |
|
<emphasis>Spring TestContext Framework</emphasis> with explicit |
|
<classname>ApplicationContext</classname> testing support in a |
|
JUnit 4.7 environment.</para> |
|
|
|
<para>When you extend |
|
<classname>AbstractJUnit4SpringContextTests</classname> you will |
|
have access to the following <literal>protected</literal> |
|
instance variables:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>applicationContext</literal>: use this to |
|
perform explicit bean lookups or to test the state of the |
|
context as a whole.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><classname>AbstractTransactionalJUnit4SpringContextTests</classname>:</para> |
|
|
|
<para>Abstract <emphasis>transactional</emphasis> extension of |
|
<classname>AbstractJUnit4SpringContextTests</classname> that |
|
also adds some convenience functionality for JDBC access. |
|
Expects a <classname>javax.sql.DataSource</classname> bean and a |
|
<interfacename>PlatformTransactionManager</interfacename> bean |
|
to be defined in the |
|
<classname>ApplicationContext</classname>.</para> |
|
|
|
<para>When you extend |
|
<classname>AbstractTransactionalJUnit4SpringContextTests</classname> |
|
you will have access to the following |
|
<literal>protected</literal> instance variables:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>applicationContext</literal>: inherited from |
|
the <classname>AbstractJUnit4SpringContextTests</classname> |
|
superclass. Use this to perform explicit bean lookups or to |
|
test the state of the context as a whole.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>simpleJdbcTemplate</literal>: useful for |
|
querying to confirm state. For example, you might query |
|
before and after testing application code that creates an |
|
object and persists it using an ORM tool, to verify that the |
|
data appears in the database. (Spring will ensure that the |
|
query runs in the scope of the same transaction.) You will |
|
need to tell your ORM tool to 'flush' its changes for this |
|
to work correctly, for example using the |
|
<methodname>flush()</methodname> method on Hibernate's |
|
<classname>Session</classname> interface.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<tip> |
|
<para>These classes serve only as a convenience for extension. If |
|
you do not wish for your test classes to be tied to a |
|
Spring-specific class hierarchy - for example, if you wish to |
|
directly extend the class you are testing - you may configure your |
|
own custom test classes by using |
|
<interfacename>@RunWith(SpringJUnit4ClassRunner.class)</interfacename>, |
|
<interfacename>@ContextConfiguration</interfacename>, |
|
<interfacename>@TestExecutionListeners</interfacename>, |
|
etc.</para> |
|
</tip> |
|
</section> |
|
|
|
<section id="testcontext-junit4-runner"> |
|
<title>Custom JUnit 4.7 Runner</title> |
|
|
|
<para>The <emphasis>Spring TestContext Framework</emphasis> offers |
|
full integration with JUnit 4.7 via a custom runner. By annotating |
|
test classes with |
|
<literal>@Runwith(SpringJUnit4ClassRunner.class)</literal>, |
|
developers can implement standard JUnit 4.7 unit and integration |
|
tests and simultaneously reap the benefits of the TestContext |
|
framework such as support for loading application contexts, |
|
dependency injection of test instances, transactional test method |
|
execution, etc. The following code listing displays the minimal |
|
requirements for configuring a test class to run with the custom |
|
Spring Runner. <emphasis>Note that |
|
<interfacename>@TestExecutionListeners</interfacename> has been |
|
configured with an empty list in order to disable the default |
|
listeners, which would otherwise require that an |
|
<interfacename>ApplicationContext</interfacename> be configured via |
|
<interfacename>@ContextConfiguration</interfacename>.</emphasis></para> |
|
|
|
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class) |
|
@TestExecutionListeners({}) |
|
public class SimpleTest { |
|
|
|
@Test |
|
public void testMethod() { |
|
<lineannotation>// execute test logic...</lineannotation> |
|
} |
|
}</programlisting> |
|
</section> |
|
|
|
<section id="testcontext-support-classes-testng"> |
|
<title>TestNG support classes</title> |
|
|
|
<para>The <literal>org.springframework.test.context.testng</literal> |
|
package provides support classes for TestNG based test cases.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><classname>AbstractTestNGSpringContextTests</classname>:</para> |
|
|
|
<para>Abstract base test class which integrates the |
|
<emphasis>Spring TestContext Framework</emphasis> with explicit |
|
<classname>ApplicationContext</classname> testing support in a |
|
TestNG environment.</para> |
|
|
|
<para>When you extend |
|
<classname>AbstractTestNGSpringContextTests</classname> you will |
|
have access to the following <literal>protected</literal> |
|
instance variables:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>applicationContext</literal>: use this to |
|
perform explicit bean lookups or to test the state of the |
|
context as a whole.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><classname>AbstractTransactionalTestNGSpringContextTests</classname>:</para> |
|
|
|
<para>Abstract <emphasis>transactional</emphasis> extension of |
|
<classname>AbstractTestNGSpringContextTests</classname> that |
|
adds some convenience functionality for JDBC access. Expects a |
|
<classname>javax.sql.DataSource</classname> bean and a |
|
<interfacename>PlatformTransactionManager</interfacename> bean |
|
to be defined in the |
|
<classname>ApplicationContext</classname>.</para> |
|
|
|
<para>When you extend |
|
<classname>AbstractTransactionalTestNGSpringContextTests</classname> |
|
you will have access to the following |
|
<literal>protected</literal> instance variables:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><literal>applicationContext</literal>: inherited from |
|
the <classname>AbstractTestNGSpringContextTests</classname> |
|
superclass. Use this to perform explicit bean lookups or to |
|
test the state of the context as a whole.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><literal>simpleJdbcTemplate</literal>: useful for |
|
querying to confirm state. For example, you might query |
|
before and after testing application code that creates an |
|
object and persists it using an ORM tool, to verify that the |
|
data appears in the database. (Spring will ensure that the |
|
query runs in the scope of the same transaction.) You will |
|
need to tell your ORM tool to 'flush' its changes for this |
|
to work correctly, for example using the |
|
<methodname>flush()</methodname> method on Hibernate's |
|
<classname>Session</classname> interface.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<tip> |
|
<para>These classes serve only as a convenience for extension. If |
|
you do not wish for your test classes to be tied to a |
|
Spring-specific class hierarchy - for example, if you wish to |
|
directly extend the class you are testing - you may configure your |
|
own custom test classes by using |
|
<interfacename>@ContextConfiguration</interfacename>, |
|
<interfacename>@TestExecutionListeners</interfacename>, etc. and |
|
by manually instrumenting your test class with a |
|
<classname>TestContextManager</classname>. See the source code of |
|
<classname>AbstractTestNGSpringContextTests</classname> for an |
|
example of how to instrument your test class.</para> |
|
</tip> |
|
</section> |
|
</section> |
|
|
|
<!-- ================================================================= --> |
|
</section> |
|
|
|
<!-- === PetClinic Example ================================================= --> |
|
|
|
<section id="testing-examples-petclinic"> |
|
<title>PetClinic example</title> |
|
|
|
<para>The PetClinic sample application included with the full Spring |
|
distribution illustrates several features of the <emphasis>Spring |
|
TestContext Framework</emphasis> in a JUnit 4.7 environment. Most test |
|
functionality is included in the |
|
<classname>AbstractClinicTests</classname>, for which a partial listing |
|
is shown below:</para> |
|
|
|
<programlisting language="java">import static org.junit.Assert.assertEquals; |
|
<lineannotation>// import ...</lineannotation> |
|
|
|
<emphasis role="bold">@ContextConfiguration</emphasis> |
|
public abstract class AbstractClinicTests <emphasis role="bold">extends AbstractTransactionalJUnit4SpringContextTests</emphasis> { |
|
|
|
<emphasis role="bold">@Autowired</emphasis> |
|
protected Clinic clinic; |
|
|
|
@Test |
|
public void getVets() { |
|
Collection<Vet> vets = this.clinic.getVets(); |
|
assertEquals("JDBC query must show the same number of vets", |
|
<emphasis role="bold">super.countRowsInTable("VETS")</emphasis>, vets.size()); |
|
Vet v1 = EntityUtils.getById(vets, Vet.class, 2); |
|
assertEquals("Leary", v1.getLastName()); |
|
assertEquals(1, v1.getNrOfSpecialties()); |
|
assertEquals("radiology", (v1.getSpecialties().get(0)).getName()); |
|
<lineannotation>// ...</lineannotation> |
|
} |
|
|
|
<lineannotation>// ...</lineannotation> |
|
}</programlisting> |
|
|
|
<para>Notes:</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para>This test case extends the |
|
<classname>AbstractTransactionalJUnit4SpringContextTests</classname> |
|
class, from which it inherits configuration for Dependency Injection |
|
(via the |
|
<classname>DependencyInjectionTestExecutionListener</classname>) and |
|
transactional behavior (via the |
|
<classname>TransactionalTestExecutionListener</classname>).</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>The <literal>clinic</literal> instance variable - the |
|
application object being tested - is set by Dependency Injection via |
|
<interfacename>@Autowired</interfacename> semantics.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>The <methodname>testGetVets()</methodname> method illustrates |
|
how the inherited <methodname>countRowsInTable()</methodname> method |
|
can be used to easily verify the number of rows in a given table, |
|
thus testing correct behavior of the application code being tested. |
|
This allows for stronger tests and lessens dependency on the exact |
|
test data. For example, you can add additional rows in the database |
|
without breaking tests.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para>Like many integration tests using a database, most of the |
|
tests in <classname>AbstractClinicTests</classname> 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.</para> |
|
</listitem> |
|
</itemizedlist> |
|
|
|
<para>The PetClinic application supports three data access technologies |
|
- JDBC, Hibernate, and JPA. By declaring |
|
<interfacename>@ContextConfiguration</interfacename> without any |
|
specific resource locations, the |
|
<classname>AbstractClinicTests</classname> class will have its |
|
application context loaded from the default location, |
|
<literal>"AbstractClinicTests-context.xml"</literal>, which declares a |
|
common <classname>DataSource</classname>. Subclasses specify additional |
|
context locations which must declare a |
|
<interfacename>PlatformTransactionManager</interfacename> and a concrete |
|
implementation of <interfacename>Clinic</interfacename>.</para> |
|
|
|
<para>For example, the Hibernate implementation of the PetClinic tests |
|
contains the following implementation. Note that for this example, |
|
<classname>HibernateClinicTests</classname> does not contain a single |
|
line of code: we only need to declare |
|
<interfacename>@ContextConfiguration</interfacename>, and the tests are |
|
inherited from <classname>AbstractClinicTests</classname>. Since |
|
<interfacename>@ContextConfiguration</interfacename> is declared without |
|
any specific resource locations, the <emphasis>Spring TestContext |
|
Framework</emphasis> will load an application context from all the beans |
|
defined in <literal>"AbstractClinicTests-context.xml"</literal> (i.e., |
|
the inherited locations) and |
|
<literal>"HibernateClinicTests-context.xml"</literal>, with |
|
<literal>"HibernateClinicTests-context.xml"</literal> possibly |
|
overriding beans defined in |
|
<literal>"AbstractClinicTests-context.xml"</literal>.</para> |
|
|
|
<programlisting language="java"><emphasis role="bold">@ContextConfiguration</emphasis> |
|
public class HibernateClinicTests extends AbstractClinicTests { } |
|
</programlisting> |
|
|
|
<para>As you can see in the PetClinic application, the Spring |
|
configuration is split across multiple files. As is typical of large |
|
scale applications, configuration locations will often be 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 |
|
<classname>HibernateTemplate</classname>, in the case of an application |
|
using Hibernate.</para> |
|
|
|
<para>As far as possible, you should have exactly the same Spring |
|
configuration files in your integration tests as in the deployed |
|
environment. One likely point of difference concerns database connection |
|
pooling and transaction infrastructure. If you are deploying to a |
|
full-blown application server, you will probably use its connection pool |
|
(available through JNDI) and JTA implementation. Thus in production you |
|
will use a <classname>JndiObjectFactoryBean</classname> / |
|
<literal><jee:jndi-lookup></literal> for the |
|
<classname>DataSource</classname> and |
|
<classname>JtaTransactionManager</classname>. JNDI and JTA will not be |
|
available in out-of-container integration tests, so you should use a |
|
combination like the Commons DBCP <classname>BasicDataSource</classname> |
|
and <classname>DataSourceTransactionManager</classname> or |
|
<classname>HibernateTransactionManager</classname> for them. You can |
|
factor out this variant behavior into a single XML file, having the |
|
choice between application server and 'local' configuration separated |
|
from all other configuration, which will not vary between the test and |
|
production environments. In addition, it is advisable to use properties |
|
files for connection settings: see the PetClinic application for an |
|
example.</para> |
|
</section> |
|
|
|
<!-- ======================================================================= --> |
|
</section> |
|
|
|
<section id="testing-resources"> |
|
<title>Further Resources</title> |
|
|
|
<para>This section contains links to further resources about testing in |
|
general.</para> |
|
|
|
<itemizedlist> |
|
<listitem> |
|
<para><ulink url="http://www.junit.org/">JUnit</ulink>: the Spring |
|
Framework's unit and integration test suite is written using JUnit 3.8 |
|
and JUnit 4.7 as the testing framework.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><ulink url="http://testng.org/">TestNG</ulink>: a testing |
|
framework inspired by JUnit 3.8 with added support for Java 5 |
|
annotations, test groups, data-driven testing, distributed testing, |
|
etc.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><ulink |
|
url="http://www.mockobjects.com/">MockObjects.com</ulink>: a website |
|
dedicated to mock objects, a technique for improving the design of |
|
code within Test-Driven Development.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><ulink url="http://en.wikipedia.org/wiki/Mock_Object">"Mock |
|
Objects"</ulink>: article at Wikipedia.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><ulink url="http://www.easymock.org/">EasyMock</ulink>: the |
|
Spring Framework uses EasyMock extensively in its test suite.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><ulink url="http://www.jmock.org/">JMock</ulink>: a library that |
|
supports test-driven development of Java code with mock |
|
objects.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><ulink url="http://mockito.org/">Mockito</ulink>: a Java mock |
|
library based on the <ulink url="http://xunitpatterns.com/Test%20Spy.html">test spy</ulink> |
|
pattern.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><ulink url="http://dbunit.sourceforge.net/">DbUnit</ulink>: a |
|
JUnit extension (also usable with Ant and Maven) targeted for |
|
database-driven projects that, among other things, puts your database |
|
into a known state between test runs.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><ulink url="http://grinder.sourceforge.net/">Grinder</ulink>: a |
|
Java load testing framework.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</section> |
|
</chapter>
|
|
|