Document WebApplicationContext support in the TCF

This commit adds documentation for the following new features in the
Spring TestContext Framework within the Testing chapter of the reference
manual.

 - @WebAppConfiguration and context caching
 - WebDelegatingSmartContextLoader
 - AnnotationConfigWebContextLoader
 - GenericXmlWebContextLoader
 - Loading a WebApplicationContext in integration tests
 - ServletTestExecutionListener
 - Testing request and session scoped beans

Issue: SPR-9864
This commit is contained in:
Sam Brannen 2012-12-12 00:56:26 +01:00
parent 7f1b990ee9
commit a1053d4364
1 changed files with 547 additions and 106 deletions

View File

@ -265,15 +265,16 @@
<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 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
mapping files, and incurring that cost before running every test in
every test fixture leads to slower overall test runs that reduce
developer productivity.</para>
Spring <classname>ApplicationContext</classname>s and
<classname>WebApplicationContext</classname>s as well as 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 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 mapping files, and incurring that cost before running every
test in every test fixture leads to slower overall test runs that
reduce developer productivity.</para>
<para>Test classes typically declare either an array of
<emphasis>resource locations</emphasis> for XML configuration metadata
@ -526,6 +527,55 @@ public class CustomLoaderXmlApplicationContextTests {
details.</para>
</listitem>
<listitem>
<para><emphasis
role="bold"><interfacename>@WebAppConfiguration</interfacename></emphasis></para>
<para>A class-level annotation that is used to declare that the
<interfacename>ApplicationContext</interfacename> loaded for an
integration test should be a
<interfacename>WebApplicationContext</interfacename>. The mere
presence of <interfacename>@WebAppConfiguration</interfacename> on
a test class ensures that a
<interfacename>WebApplicationContext</interfacename> will be
loaded for the test, using the default value of
<literal>"file:src/main/webapp"</literal> for the path to the root
of the web application (i.e., the <emphasis>resource base
path</emphasis>). The resource base path is used behind the scenes
to create a <classname>MockServletContext</classname> which serves
as the <interfacename>ServletContext</interfacename> for the
test's
<interfacename>WebApplicationContext</interfacename>.</para>
<programlisting language="java">@ContextConfiguration
<emphasis role="bold">@WebAppConfiguration</emphasis>
public class WebAppTests {
<lineannotation>// class body...</lineannotation>
}</programlisting>
<para>To override the default, specify a different base resource
path via the <emphasis>implicit</emphasis>
<interfacename>value</interfacename> attribute. Both
<literal>classpath:</literal> and <literal>file:</literal>
resource prefixes are supported. If no resource prefix is supplied
the path is assumed to be a file system resource.</para>
<programlisting language="java">@ContextConfiguration
<emphasis role="bold">@WebAppConfiguration("classpath:test-web-resources")</emphasis>
public class WebAppTests {
<lineannotation>// class body...</lineannotation>
}</programlisting>
<para>Note that
<interfacename>@WebAppConfiguration</interfacename> must be used
in conjunction with
<interfacename>@ContextConfiguration</interfacename>, either
within a single test class or within a test class hierarchy. See
the Javadoc for
<interfacename>@WebAppConfiguration</interfacename> for further
details.</para>
</listitem>
<listitem>
<para><emphasis role="bold">
<interfacename>@ActiveProfiles</interfacename> </emphasis></para>
@ -1107,14 +1157,16 @@ public void testProcessRepeatedly() {
<classname>TestContextManager</classname> with which the listener
is registered.</para>
<para>Spring provides three
<para>Spring provides four
<interfacename>TestExecutionListener</interfacename>
implementations that are configured by default:
<classname>ServletTestExecutionListener</classname>,
<classname>DependencyInjectionTestExecutionListener</classname>,
<classname>DirtiesContextTestExecutionListener</classname>, and
<classname>TransactionalTestExecutionListener</classname>.
Respectively, they support dependency injection of the test
instance, handling of the
Respectively, they support Servlet API mocks for a
<interfacename>WebApplicationContext</interfacename>, dependency
injection of the test instance, handling of the
<interfacename>@DirtiesContext</interfacename> annotation, and
transactional test execution with default rollback
semantics.</para>
@ -1142,18 +1194,18 @@ public void testProcessRepeatedly() {
supersedes the <interfacename>ContextLoader</interfacename> SPI
that was introduced in Spring 2.5. Specifically, a
<interfacename>SmartContextLoader</interfacename> can choose to
process either resource <varname>locations</varname> or annotated
<varname>classes</varname>. Furthermore, a
process resource <varname>locations</varname>, annotated
<varname>classes</varname>, or context
<varname>initializers</varname>. Furthermore, a
<interfacename>SmartContextLoader</interfacename> can set active
bean definition profiles in the context that it loads.</para>
<para>Spring provides the following out-of-the-box
implementations:</para>
<para>Spring provides the following implementations:</para>
<itemizedlist>
<listitem>
<para><classname>DelegatingSmartContextLoader</classname>: the
default loader which delegates internally to an
<para><classname>DelegatingSmartContextLoader</classname>: one
of two default loaders which delegates internally to an
<classname>AnnotationConfigContextLoader</classname> or a
<classname>GenericXmlContextLoader</classname> depending
either on the configuration declared for the test class or on
@ -1162,21 +1214,48 @@ public void testProcessRepeatedly() {
</listitem>
<listitem>
<para><classname>AnnotationConfigContextLoader</classname>:
loads an application context from <emphasis>annotated
classes</emphasis>.</para>
<para><classname>WebDelegatingSmartContextLoader</classname>:
one of two default loaders which delegates internally to an
<classname>AnnotationConfigWebContextLoader</classname> or a
<classname>GenericXmlWebContextLoader</classname> depending
either on the configuration declared for the test class or on
the presence of default locations or default configuration
classes. A web <interfacename>ContextLoader</interfacename>
will only be used if
<interfacename>@WebAppConfiguration</interfacename> is present
on the test class.</para>
</listitem>
<listitem>
<para><classname>GenericXmlContextLoader</classname>: loads an
application context from XML <emphasis>resource
locations</emphasis>.</para>
<para><classname>AnnotationConfigContextLoader</classname>:
loads a standard
<interfacename>ApplicationContext</interfacename> from
<emphasis>annotated classes</emphasis>.</para>
</listitem>
<listitem>
<para><classname>AnnotationConfigWebContextLoader</classname>:
loads a <interfacename>WebApplicationContext</interfacename>
from <emphasis>annotated classes</emphasis>.</para>
</listitem>
<listitem>
<para><classname>GenericXmlContextLoader</classname>: loads a
standard <interfacename>ApplicationContext</interfacename>
from XML <emphasis>resource locations</emphasis>.</para>
</listitem>
<listitem>
<para><classname>GenericXmlWebContextLoader</classname>: loads
a <interfacename>WebApplicationContext</interfacename> from
XML <emphasis>resource locations</emphasis>.</para>
</listitem>
<listitem>
<para><classname>GenericPropertiesContextLoader</classname>:
loads an application context from Java Properties
files.</para>
loads a standard
<interfacename>ApplicationContext</interfacename> from Java
Properties files.</para>
</listitem>
</itemizedlist>
</listitem>
@ -1194,8 +1273,8 @@ public void testProcessRepeatedly() {
<para>Each <classname>TestContext</classname> provides context
management and caching support for the test instance it is responsible
for. Test instances do not automatically receive access to the
configured <classname>ApplicationContext</classname>. However, if a
test class implements the
configured <interfacename>ApplicationContext</interfacename>. However,
if a test class implements the
<interfacename>ApplicationContextAware</interfacename> interface, a
reference to the <classname>ApplicationContext</classname> is supplied
to the test instance. Note that
@ -1203,7 +1282,7 @@ public void testProcessRepeatedly() {
<classname>AbstractTestNGSpringContextTests</classname> implement
<interfacename>ApplicationContextAware</interfacename> and therefore
provide access to the <classname>ApplicationContext</classname>
out-of-the-box.</para>
automatically.</para>
<tip>
<title>@Autowired ApplicationContext</title>
@ -1221,6 +1300,21 @@ public class MyTest {
<emphasis role="bold">@Autowired</emphasis>
private ApplicationContext applicationContext;
<lineannotation>// class body...</lineannotation>
}</programlisting>
<para>Similarly, if your test is configured to load a
<interfacename>WebApplicationContext</interfacename>, you can inject
the web application context into your test as follows:</para>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
<emphasis role="bold">@WebAppConfiguration</emphasis>
@ContextConfiguration
public class MyWebAppTest {
<emphasis role="bold">@Autowired</emphasis>
private WebApplicationContext wac;
<lineannotation>// class body...</lineannotation>
}</programlisting>
@ -1781,12 +1875,207 @@ public class TransferServiceTest {
<!-- TODO Consider documenting inheritance for active profiles. -->
</section>
<section xml:id="testcontext-ctx-management-web">
<title>Loading a WebApplicationContext</title>
<para>Spring 3.2 introduces support for loading a
<interfacename>WebApplicationContext</interfacename> in integration
tests. To instruct the TestContext framework to load a
<interfacename>WebApplicationContext</interfacename> instead of a
standard <interfacename>ApplicationContext</interfacename>, simply
annotate the respective test class with
<interfacename>@WebAppConfiguration</interfacename>.</para>
<para>The presence of
<interfacename>@WebAppConfiguration</interfacename> on your test
class instructs the TestContext framework (TCF) that a
<interfacename>WebApplicationContext</interfacename> (WAC) should be
loaded for your integration tests. In the background the TCF makes
sure that a <interfacename>MockServletContext</interfacename> is
created and supplied to your test's WAC. By default the base
resource path for your
<interfacename>MockServletContext</interfacename> will be set to
<emphasis>"src/main/webapp"</emphasis>. This is interpreted as a
path relative to the root of your JVM (i.e., normally the path to
your project). If you're familiar with the directory structure of a
web application in a Maven project, you'll know that
<emphasis>"src/main/webapp"</emphasis> is the default location for
the root of your WAR. If you need to override this default, simply
provide an alternate path to the
<interfacename>@WebAppConfiguration</interfacename> annotation
(e.g.,
<interfacename>@WebAppConfiguration("src/test/webapp")</interfacename>).
If you wish to reference a base resource path from the classpath
instead of the file system, just use Spring's
<emphasis>classpath:</emphasis> prefix.</para>
<para>Please note that Spring's testing support for
<interfacename>WebApplicationContexts</interfacename> is on par with
its support for standard
<interfacename>ApplicationContexts</interfacename>. When testing
with a <interfacename>WebApplicationContext</interfacename> you are
free to declare either XML configuration files or
<interfacename>@Configuration</interfacename> classes via
<interfacename>@ContextConfiguration</interfacename>. You are of
course also free to use any other test annotations such as
<interfacename>@TestExecutionListeners</interfacename>,
<interfacename>@TransactionConfiguration</interfacename>,
<interfacename>@ActiveProfiles</interfacename>, etc.</para>
<para>The following examples demonstrate some of the various
configuration options for loading a
<interfacename>WebApplicationContext</interfacename>.</para>
<example>
<title>Conventions</title>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
// defaults to "file:src/main/webapp"
@WebAppConfiguration
// detects "WacTests-context.xml" in same package
// or static nested @Configuration class
@ContextConfiguration
public class WacTests {
//...
}</programlisting>
</example>
<para>The above example demonstrates the TestContext framework's
support for <emphasis>convention over configuration</emphasis>. If
you annotate a test class with
<interfacename>@WebAppConfiguration</interfacename> without
specifying a resource base path, the resource path will effectively
default to <emphasis>"file:src/main/webapp"</emphasis>. Similarly,
if you declare <interfacename>@ContextConfiguration</interfacename>
without specifying resource
<interfacename>locations</interfacename>, annotated
<interfacename>classes</interfacename>, or context
<interfacename>initializers</interfacename>, Spring will attempt to
detect the presence of your configuration using conventions (i.e.,
<emphasis>"WacTests-context.xml"</emphasis> in the same package as
the <interfacename>WacTests</interfacename> class or static nested
<interfacename>@Configuration</interfacename> classes).</para>
<example>
<title>Default Resource Semantics</title>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
// file system resource
@WebAppConfiguration("webapp")
// classpath resource
@ContextConfiguration("/spring/test-servlet-config.xml")
public class WacTests {
//...
}</programlisting>
</example>
<para>This example demonstrates how to explicitly declare a resource
base path with <interfacename>@WebAppConfiguration</interfacename>
and an XML resource location with
<interfacename>@ContextConfiguration</interfacename>. The important
thing to note here is the different semantics for paths with these
two annotations. By default,
<interfacename>@WebAppConfiguration</interfacename> resource paths
are file system based; whereas,
<interfacename>@ContextConfiguration</interfacename> resource
locations are classpath based.</para>
<example>
<title>Explicit Resource Semantics</title>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
// classpath resource
@WebAppConfiguration("classpath:test-web-resources")
// file system resource
@ContextConfiguration("file:src/main/webapp/WEB-INF/servlet-config.xml")
public class WacTests {
//...
}</programlisting>
</example>
<para>In this third example, we see that we can override the default
resource semantics for both annotations by specifying a Spring
resource prefix. Contrast the comments in this example with the
previous example.</para>
<section xml:id="testcontext-ctx-management-web-mocks">
<title>Working with Web Mocks</title>
<para>To provide comprehensive web testing support, Spring 3.2
introduces a new
<interfacename>ServletTestExecutionListener</interfacename> that
is enabled by default. When testing against a
<interfacename>WebApplicationContext</interfacename> this <link
linkend="testcontext-key-abstractions">TestExecutionListener</link>
sets up default thread-local state via Spring Web's
<interfacename>RequestContextHolder</interfacename> before each
test method and creates a
<interfacename>MockHttpServletRequest</interfacename>,
<interfacename>MockHttpServletResponse</interfacename>, and
<interfacename>ServletWebRequest</interfacename> based on the base
resource path configured via
<interfacename>@WebAppConfiguration</interfacename>.
<interfacename>ServletTestExecutionListener</interfacename> also
ensures that the
<interfacename>MockHttpServletResponse</interfacename> and
<interfacename>ServletWebRequest</interfacename> can be injected
into the test instance, and once the test is complete it cleans up
thread-local state.</para>
<para>Once you have a
<interfacename>WebApplicationContext</interfacename> loaded for
your test you might find that you need to interact with the web
mocks — for example, to set up your test fixture or to perform
assertions after invoking your web component. The following
example demonstrates which mocks can be autowired into your test
instance. Note that the
<interfacename>WebApplicationContext</interfacename> and
<interfacename>MockServletContext</interfacename> are both cached
across the test suite; whereas, the other mocks are managed per
test method by the
<interfacename>ServletTestExecutionListener</interfacename>.</para>
<example>
<title>Injecting Mocks</title>
<programlisting language="java">@WebAppConfiguration
@ContextConfiguration
public class WacTests {
@Autowired WebApplicationContext wac; // cached
@Autowired MockServletContext servletContext; // cached
@Autowired MockHttpSession session;
@Autowired MockHttpServletRequest request;
@Autowired MockHttpServletResponse response;
@Autowired ServletWebRequest webRequest;
//...
}</programlisting>
</example>
</section>
</section>
<section xml:id="testcontext-ctx-management-caching">
<title>Context caching</title>
<para>Once the TestContext framework loads an
<interfacename>ApplicationContext</interfacename> for a test, that
context will be cached and reused for <emphasis
<interfacename>ApplicationContext</interfacename> (or
<interfacename>WebApplicationContext</interfacename>) for a test,
that context will be cached and reused for <emphasis
role="bold">all</emphasis> subsequent tests that declare the same
unique context configuration within the same test suite. To
understand how caching works, it is important to understand what is
@ -1826,6 +2115,11 @@ public class TransferServiceTest {
<para><varname>activeProfiles</varname> <emphasis>(from
@ActiveProfiles)</emphasis></para>
</listitem>
<listitem>
<para><varname>resourceBasePath</varname> <emphasis>(from
@WebAppConfiguration)</emphasis></para>
</listitem>
</itemizedlist>
<para>For example, if <classname>TestClassA</classname> specifies
@ -1838,7 +2132,8 @@ public class TransferServiceTest {
solely on those locations. So if <classname>TestClassB</classname>
also defines <literal>{"app-config.xml",
"test-config.xml"}</literal> for its locations (either explicitly or
implicitly through inheritance) and does not define a different
implicitly through inheritance) but does not define
<interfacename>@WebAppConfiguration</interfacename>, a different
<interfacename>ContextLoader</interfacename>, different active
profiles, or different context initializers, then the same
<interfacename>ApplicationContext</interfacename> will be shared by
@ -2055,6 +2350,170 @@ public class HibernateTitleRepositoryTests {
</note>
</section>
<section xml:id="testcontext-web-scoped-beans">
<title>Testing request and session scoped beans</title>
<para><link linkend="beans-factory-scopes-other">Request and session
scoped beans</link> have been supported by Spring for several years
now, but it's always been a bit non-trivial to test them. As of Spring
3.2 it's now a breeze to test your request-scoped and session-scoped
beans by following these steps.</para>
<itemizedlist>
<listitem>
<para>Ensure that a
<interfacename>WebApplicationContext</interfacename> is loaded for
your test by annotating your test class with
<interfacename>@WebAppConfiguration</interfacename>.</para>
</listitem>
<listitem>
<para>Inject the mock request or session into your test instance
and prepare your test fixture as appropriate.</para>
</listitem>
<listitem>
<para>Invoke your web component that you retrieved from the
configured <interfacename>WebApplicationContext</interfacename>
(i.e., via dependency injection).</para>
</listitem>
<listitem>
<para>Perform assertions against the mocks.</para>
</listitem>
</itemizedlist>
<para>The following code snippet displays the XML configuration for a
login use case. Note that the <literal>userService</literal> bean has
a dependency on a request-scoped <literal>loginAction</literal> bean.
Also, the <classname>LoginAction</classname> is instantiated using
<link linkend="expressions">SpEL expressions</link> that retrieve the
username and password from the current HTTP request. In our test, we
will want to configure these request parameters via the mock managed
by the TestContext framework.</para>
<example>
<title>Request-scoped bean configuration</title>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="userService"
class="com.example.SimpleUserService"
c:loginAction-ref="loginAction" /&gt;
&lt;bean id="loginAction" class="com.example.LoginAction"
c:username="#{request.getParameter('user')}"
c:password="#{request.getParameter('pswd')}"
scope="request"&gt;
&lt;aop:scoped-proxy /&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
</example>
<para>In <classname>RequestScopedBeanTests</classname> we inject both
the <classname>UserService</classname> (i.e., the subject under test)
and the <classname>MockHttpServletRequest</classname> into our test
instance. Within our <function>requestScope()</function> test method
we set up our test fixture by setting request parameters in the
provided <classname>MockHttpServletRequest</classname>. When the
<function>loginUser()</function> method is invoked on our
<literal>userService</literal> we are assured that the user service
has access to the request-scoped <literal>loginAction</literal> for
the current <classname>MockHttpServletRequest</classname> (i.e., the
one we just set parameters in). We can then perform assertions against
the results based on the known inputs for the username and
password.</para>
<example>
<title>Request-scoped bean test</title>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class RequestScopedBeanTests {
@Autowired UserService userService;
@Autowired MockHttpServletRequest request;
@Test
public void requestScope() {
request.setParameter("user", "enigma");
request.setParameter("pswd", "$pr!ng");
LoginResults results = userService.loginUser();
// assert results
}
}</programlisting>
</example>
<para>The following code snippet is similar to the one we saw above
for a request-scoped bean; however, this time the
<literal>userService</literal> bean has a dependency on a
session-scoped <literal>userPreferences</literal> bean. Note that the
<classname>UserPreferences</classname> bean is instantiated using a
SpEL expression that retrieves the <emphasis>theme</emphasis> from the
current HTTP session. In our test, we will need to configure a theme
in the mock session managed by the TestContext framework.</para>
<example>
<title>Session-scoped bean configuration</title>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="userService"
class="com.example.SimpleUserService"
c:userPreferences-ref="userPreferences" /&gt;
&lt;bean id="userPreferences"
class="com.example.UserPreferences"
c:theme="#{session.getAttribute('theme')}"
scope="session"&gt;
&lt;aop:scoped-proxy /&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
</example>
<para>In <classname>SessionScopedBeanTests</classname> we inject the
<classname>UserService</classname> and the
<classname>MockHttpSession</classname> into our test instance. Within
our <function>sessionScope()</function> test method we set up our test
fixture by setting the expected "theme" attribute in the provided
<classname>MockHttpSession</classname>. When the
<function>processUserPreferences()</function> method is invoked on our
<literal>userService</literal> we are assured that the user service
has access to the session-scoped <literal>userPreferences</literal>
for the current <classname>MockHttpSession</classname>, and we can
perform assertions against the results based on the configured
theme.</para>
<example>
<title>Session-scoped bean test</title>
<programlisting language="java">@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class SessionScopedBeanTests {
@Autowired UserService userService;
@Autowired MockHttpSession session;
@Test
public void sessionScope() throws Exception {
session.setAttribute("theme", "blue");
Results results = userService.processUserPreferences();
// assert results
}
}</programlisting>
</example>
</section>
<section xml:id="testcontext-tx">
<title>Transaction management</title>
@ -2420,10 +2879,10 @@ public class SimpleTest {
<para>The <filename>spring-test</filename> module uses a different
package <classname>org.springframework.test.web</classname> but
otherwise is nearly identical with two exceptions. One is support for
features new in 3.2 (e.g. async web requests). The other relates to
the options for creating a <classname>MockMvc</classname> instance. In
Spring Framework 3.2, this can only be done through the TestContext
framework, which provides caching benefits for the loaded
features new in 3.2 (e.g. asynchronous web requests). The other
relates to the options for creating a <classname>MockMvc</classname>
instance. In Spring Framework 3.2, this can only be done through the
TestContext framework, which provides caching benefits for the loaded
configuration.</para>
</sidebar>
@ -2432,12 +2891,13 @@ public class SimpleTest {
through a fluent API. Typically it loads the actual Spring configuration
through the <emphasis>TestContext framework</emphasis> and always uses
the <classname>DispatcherServlet</classname> to process requests thus
approximating full integration tests without requiring a running servlet
approximating full integration tests without requiring a running Servlet
container.</para>
<para>Client-side tests are <classname>RestTemplate</classname>-based
and allow tests for code that relies on the <code>RestTemplate</code>
without requiring a running server to respond to the requests.</para>
and allow tests for code that relies on the
<classname>RestTemplate</classname> without requiring a running server
to respond to the requests.</para>
<section xml:id="spring-mvc-test-server">
<title>Server-Side Tests</title>
@ -2476,8 +2936,8 @@ public class SimpleTest {
<classname>MockHttpServletResponse</classname> works, you'll know that
forwards and redirects are not actually executed. Instead "forwarded"
and "redirected" URLs are saved and can be asserted in tests. This
means if you are using JSPs, you can verify the JSP page to which the request was
forwarded.</para>
means if you are using JSPs, you can verify the JSP page to which the
request was forwarded.</para>
<para>All other means of rendering including
<interfacename>@ResponseBody</interfacename> methods and
@ -2520,10 +2980,10 @@ public class ExampleTests {
<para>The test relies on the
<interfacename>WebApplicationContext</interfacename> support of the
<emphasis>TestContext framework</emphasis>. It loads Spring
configuration from an XML config file located in the same package as
the test class (also supports Java config) and injects the created
<interfacename>WebApplicationContext</interfacename> into the test so
a <classname>MockMvc</classname> instance can be created with
configuration from an XML configuration file located in the same
package as the test class (also supports JavaConfig) and injects the
created <interfacename>WebApplicationContext</interfacename> into the
test so a <classname>MockMvc</classname> instance can be created with
it.</para>
<para>The <classname>MockMvc</classname> is then used to perform a
@ -2589,7 +3049,7 @@ public class MyWebTests {
without loading any Spring configuration. Instead basic Spring MVC
configuration suitable for testing annotated controllers is
automatically created. The created configuration is comparable to
that of the MVC Java config (and the MVC namespace) and can be
that of the MVC JavaConfig (and the MVC namespace) and can be
customized to a degree through builder-style methods:</para>
<programlisting language="java">public class MyWebTests {
@ -2616,8 +3076,7 @@ public class MyWebTests {
remain focused on testing the web layer. Here is an example of
declaring a mock service with Mockito:</para>
<programlisting language="xml">
&lt;bean id="accountService" class="org.mockito.Mockito" factory-method="mock"&gt;
<programlisting language="xml">&lt;bean id="accountService" class="org.mockito.Mockito" factory-method="mock"&gt;
&lt;constructor-arg value="org.example.AccountService"/&gt;
&lt;/bean&gt;
</programlisting>
@ -2667,45 +3126,42 @@ public class AccountTests {
additional builder-style methods corresponding to properties of
<classname>MockHttpServletRequest</classname>. For example:</para>
<programlisting language="java">
mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));
<programlisting language="java">mockMvc.perform(post("/hotels/{id}", 42).accept(MediaType.APPLICATION_JSON));
</programlisting>
<para>In addition to all the HTTP methods, you can also perform file
upload requests, which internally creates an instance of
<classname>MockMultipartHttpServletRequest</classname>:</para>
<programlisting language="java">
mockMvc.perform(fileUpload("/doc").file("a1", "ABC".getBytes("UTF-8")));
<programlisting language="java">mockMvc.perform(fileUpload("/doc").file("a1", "ABC".getBytes("UTF-8")));
</programlisting>
<para>Query string parameters can be specified in the URI
template:</para>
<programlisting language="java">
mockMvc.perform(get("/hotels?foo={foo}", "bar"));
<programlisting language="java">mockMvc.perform(get("/hotels?foo={foo}", "bar"));
</programlisting>
<para>Or by adding Servlet request parameters:</para>
<programlisting language="java">
mockMvc.perform(get("/hotels").param("foo", "bar"));
<programlisting language="java">mockMvc.perform(get("/hotels").param("foo", "bar"));
</programlisting>
<para>If application code relies on Servlet request parameters, and
doesn't check the query string, as is most often the case, then it
doesn't matter how parameters are added. Keep in mind though that
parameters provided in the URI template will be decoded while
parameters provided through the <code>param(...)</code> method are
expected to be decoded.</para>
parameters provided through the <function>param(...)</function>
method are expected to be decoded.</para>
<para>In most cases it's preferable to leave out the context path
and the servlet path from the request URI. If you must test with the
full request URI, be sure to set the contextPath and servletPath
accordingly so that request mappings will work:</para>
and the Servlet path from the request URI. If you must test with the
full request URI, be sure to set the
<function>contextPath</function> and
<function>servletPath</function> accordingly so that request
mappings will work:</para>
<programlisting language="java">
mockMvc.perform(get("/app/main/hotels/{id}").contextPath("/app").servletPath("/main"))
<programlisting language="java">mockMvc.perform(get("/app/main/hotels/{id}").contextPath("/app").servletPath("/main"))
</programlisting>
<para>Looking at the above example, it would be cumbersome to set
@ -2713,8 +3169,7 @@ mockMvc.perform(get("/app/main/hotels/{id}").contextPath("/app").servletPath("/m
why you can define default request properties when building the
<classname>MockMvc</classname>:</para>
<programlisting language="java">
public class MyWebTests {
<programlisting language="java">public class MyWebTests {
private MockMvc mockMvc;
@ -2740,14 +3195,13 @@ public class MyWebTests {
<title>Defining Expectations</title>
<para>Expectations can be defined by appending one or more
<code>.andExpect(..)</code> after call to perform the
<function>.andExpect(..)</function> after call to perform the
request:</para>
<programlisting language="java">
mockMvc.perform(get("/accounts/1")).andExpect(status().isOk());
<programlisting language="java">mockMvc.perform(get("/accounts/1")).andExpect(status().isOk());
</programlisting>
<para><code>MockMvcResultMatchers.*</code> defines a number of
<para><literal>MockMvcResultMatchers.*</literal> defines a number of
static members, some of which return types with additional methods,
for asserting the result of the performed request. The assertions
fall in two general categories.</para>
@ -2772,41 +3226,35 @@ mockMvc.perform(post("/persons"))
</programlisting>
<para>Many times when writing tests, it's useful to dump the result
of the performed request. This can be done as follows:</para>
of the performed request. This can be done as follows, where
<function>print()</function> is a static import from
<classname>MockMvcResultHandlers</classname>:</para>
<programlisting language="java">
mockMvc.perform(post("/persons"))
<programlisting language="java">mockMvc.perform(post("/persons"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(model().attributeHasErrors("person"));
</programlisting>
.andExpect(model().attributeHasErrors("person"));</programlisting>
<para>where <code>print()</code> is a static import from
<code>MockMvcResultHandlers</code>. As long as request processing
does cause an unhandled exception, the <code>print()</code> method
will print all the available result data to
<code>System.out</code>.</para>
<para>As long as request processing causes an unhandled exception,
the <function>print()</function> method will print all the available
result data to <literal>System.out</literal>.</para>
<para>In some cases, you may want to get direct access to the result
and verify something that cannot be verified otherwise. This can be
done by appending <code>.andReturn()</code> at the end after all
expectations:</para>
done by appending <function>.andReturn()</function> at the end after
all expectations:</para>
<programlisting language="java">
MvcResult mvcResult = mockMvc.perform(post("/persons")).andExpect(status().isOk()).andReturn();
// ...
</programlisting>
<programlisting language="java">MvcResult mvcResult = mockMvc.perform(post("/persons")).andExpect(status().isOk()).andReturn();
// ...</programlisting>
<para>When all tests repeat the same expectations, you can define
the common expectations once when building the
<classname>MockMvc</classname>:</para>
<programlisting language="java">
standaloneSetup(new SimpleController())
<programlisting language="java">standaloneSetup(new SimpleController())
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType("application/json;charset=UTF-8"))
.build()
</programlisting>
.build()</programlisting>
<para>Note that the expectation is <emphasis>always</emphasis>
applied and cannot be overridden without creating a separate
@ -2817,21 +3265,17 @@ standaloneSetup(new SimpleController())
xl:href="https://github.com/SpringSource/spring-hateoas">Spring
HATEOAS</link>, the resulting links can be verified:</para>
<programlisting language="java">
mockMvc.perform(get("/people").accept(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.links[?(@.rel == 'self')].href").value("http://localhost:8080/people"));
</programlisting>
<programlisting language="java">mockMvc.perform(get("/people").accept(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.links[?(@.rel == 'self')].href").value("http://localhost:8080/people"));</programlisting>
<para>When XML response content contains hypermedia links created
with <link
xl:href="https://github.com/SpringSource/spring-hateoas">Spring
HATEOAS</link>, the resulting links can be verified:</para>
<programlisting language="java">
Map&lt;String, String&gt; ns = Collections.singletonMap("ns", "http://www.w3.org/2005/Atom");
<programlisting language="java">Map&lt;String, String&gt; ns = Collections.singletonMap("ns", "http://www.w3.org/2005/Atom");
mockMvc.perform(get("/handle").accept(MediaType.APPLICATION_XML))
.andExpect(xpath("/person/ns:link[@rel='self']/@href", ns).string("http://localhost:8080/people"));
</programlisting>
.andExpect(xpath("/person/ns:link[@rel='self']/@href", ns).string("http://localhost:8080/people"));</programlisting>
</section>
<section xml:id="spring-mvc-test-server-filters">
@ -2841,9 +3285,7 @@ mockMvc.perform(get("/handle").accept(MediaType.APPLICATION_XML))
register one or more <interfacename>Filter</interfacename>
instances:</para>
<programlisting language="java">
mockMvc = standaloneSetup(new PersonController()).addFilters(new CharacterEncodingFilter()).build();
</programlisting>
<programlisting language="java">mockMvc = standaloneSetup(new PersonController()).addFilters(new CharacterEncodingFilter()).build();</programlisting>
<para>Registered filters will be invoked through
<classname>MockFilterChain</classname> from
@ -2870,16 +3312,14 @@ mockMvc = standaloneSetup(new PersonController()).addFilters(new CharacterEncodi
<classname>RestTemplate</classname>. The goal is to define expected
requests and provide "stub" responses:</para>
<programlisting language="java">
RestTemplate restTemplate = new RestTemplate();
<programlisting language="java">RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess("Hello world", "text/plain"));
// use RestTemplate ...
mockServer.verify();
</programlisting>
mockServer.verify();</programlisting>
<para>In the above example,
<classname>MockRestServiceServer</classname> -- the central class for
@ -2893,8 +3333,9 @@ mockServer.verify();
<para>Once expected requests and stub responses have been defined, the
<classname>RestTemplate</classname> can be used in client-side code as
usual. At the end of the tests <code>mockServer.verify()</code> can be
used to verify that all expected requests were performed.</para>
usual. At the end of the tests <literal>mockServer.verify()</literal>
can be used to verify that all expected requests were
performed.</para>
<section xml:id="spring-mvc-test-client-static-imports">
<title>Static Imports</title>