Modern application frameworks like Spring promote a POJO-based programming model, and POJOs are inherently easy to unit test. But how can we effectively integration test our application outside the container while still getting as close to a production-like environment as possible? This session will show attendees how to approximate a target production environment using the Spring TestContext Framework to drive fast, repeatable, "out-of-container" integration tests. To simulate a live system, the session will cover open source integration testing techniques such as the use of in-memory databases, JMS providers, and Servlet containers as well as mock SMTP and FTP servers.
3. Agenda
• Background
• Goals of IntegraOon TesOng
• The Challenge
• Proposed SoluOon
• DI and IoC as Enablers
• SimulaOng a ProducOon Environment
• Spring TestContext Framework
• Q&A
5. Types of Tests
• unit tests
• integraOon tests
– component interacOon: mulOple units
– cross‐process interacOon: database, mail, etc.
• system tests
– end‐to‐end tesOng with live systems
• user acceptance tests
6. Unit Tests
• are simple to set up
• use dynamic mocks or stubs for dependencies
• instanOate the SUT and test it
• run fast
• but only test a single unit
7. IntegraOon Tests
• test interacOons between mulOple
components
• relaOvely easy to set up without external
system dependencies
• challenging to set up with external system
dependencies
• more challenging when/if applicaOon code
depends on the container
15. Approximate the producOon
environment by...
• Using open source libraries and frameworks to
simulate
– a single external system dependency, or
– mulOple external system dependencies
• Using the Spring TestContext Framework to
drive fast, out‐of‐container integraOon tests
– with simulated external systems started in‐
memory
17. DI and IoC Increase Testability
• Dependencies are injected, not explicitly
instanOated
– Not only for applicaOon components, but also for
infrastructure components
• JNDI look‐ups for container provided resources
– EJBs, data sources, connecOon factories, etc.
• Programming to interfaces
– Allows us to transparently swap implementaOons
19. Step 1
• Ensure your applicaOon configuraOon can be
split into:
– applicaOon‐specific configuraOon
• business logic
• service layer, repository layer, etc.
– environment‐specific configuraOon
• infrastructure
20. Step 2
• Ensure environment‐specific components can
be easily overridden in test configuraOon – for
example, by using well defined bean IDs.
– DataSource: dataSource
– PladormTransacOonManager:
transac9onManager
– JMS ConnecOonFactory: connec9onFactory
21. Step 3
• Use open source replacements for
environment‐specific components
– preferably configurable via Spring
ApplicaOonContext
– typically in‐memory (a.k.a., embedded mode)
26. Populate Database in XML
<jdbc:initialize-database data-source="dataSource">
<jdbc:script location="classpath:/schema_01.sql" />
<jdbc:script location="classpath:/schema_02.sql" />
<jdbc:script location="classpath:/data_01.sql" />
<jdbc:script location="classpath:/data_02.sql" />
</jdbc:initialize-database>
27. JMS
• Use an in‐memory message broker such as
AcOveMQ
• AcOveMQ can be easily configured in a Spring
ApplicaOonContext
• Versions > 4.1 even provide an <amq /> XML
namespace for DSL‐like configuraOon
29. SMTP Server
• Use Dumbster's SimpleSmtpServer
– Configurable port number
– Tracks all mails sent
– Provides methods for retrieving
• Number of mails sent
• Individual mails
• Mail headers
• Mail body
30. AbstractEmailSenderTest (1/2)
public abstract class AbstractEmailSenderTest {
protected SimpleSmtpServer server;
@Before public void startSmtpServer() {
server = SimpleSmtpServer.start(getSmtpPort());
}
@After public void stopSmtpServer() {
server.stop();
}
protected abstract int getSmtpPort();
33. PlainEmailSenderTest (2/2)
@Test
public void plainEmail() throws Exception {
plainEmailSender.sendSimpleEmail(recipientEmail);
assertNumEmailsSent(server, 1);
SmtpMessage email =
(SmtpMessage) server.getReceivedEmail().next();
assertEmailHeaderValue(email, "Subject", "testing");
assertEmailHeaderValue(email, "From", "foo@bar.com");
assertEmailBodyContains(email, "This is a test email");
}
34. FTP Server
• Use MockFtpServer's
– FakeFtpServer
• Virtual or in‐memory file system
• User accounts and permissions
– StubFtpServer
• Low‐level FTP server commands
36. ConfiguraOon Tips
• Externalize connecOon se_ngs in Java
ProperOes files
• Define different ProperOes files for producOon
and tesOng
• Use Spring's PropertyPlaceholderConfigurer or
<context:property‐placeholder> for property
replacement