Effective out-of-container Integration Testing

3,679 views

Published on

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.

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,679
On SlideShare
0
From Embeds
0
Number of Embeds
50
Actions
Shares
0
Downloads
65
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Effective out-of-container Integration Testing

  1. 1. Effective out-of-container Integration Testing
 Sam
Brannen
 Swi+mind
GmbH

  2. 2. Speaker
Profile
•  Senior
So+ware
Consultant
–
Swi+mind
GmbH
•  Java
developer
with
13+
years
experience
•  Spring
Framework
Core
Developer
 –  Author
of
the
Spring
TestContext
Framework

•  Previous
SpringSource
dm
Server™
developer
•  Regular
speaker
at
conferences
on
Spring,
dm
 Server,
Java,
OSGi,
and
tesOng
•  Lead
author
of
Spring
in
a
Nutshell;
 chief
technical
reviewer
for
Spring
Recipes

  3. 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

  4. 4. Background

  5. 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. 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. 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

  8. 8. Modern
Enterprise
Java
ApplicaOons
•  Integrate
with
external
systems
 –  SMTP,
FTP,
LDAP,
RDBMS,
Web
Services,
JMS
•  Rely
on
container‐provided
funcOonality
 –  data
sources,
connecOon
factories,
transacOon
 manager

  9. 9. Goals
of
Integra3on
Tes3ng

  10. 10. EffecOve
IntegraOon
TesOng
•  Fast
•  Repeatable
•  Automated
•  Easy
to
configure
•  Provide
good
code
coverage
of
end‐to‐end
 business
use
cases

  11. 11. Out‐of‐container
•  Zero
reliance
on
availability
of
external
 systems
•  Can
be
run
anywhere
 –  developer
workstaOon
 –  CI
server
•  Approximate
a
target
producOon
environment

  12. 12. The
Challenge

  13. 13. How
can
we
effec9vely
integraOon
test
an
enterprise
Java
applicaOon...
outside
the
container...
while
sOll
ge_ng
as
close
as
possible
to
a
producOon‐like
environment?

  14. 14. Proposed
Solu3on

  15. 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

  16. 16. DI
and
IoC
as
Enablers
Dependency
Injec9on
and
Inversion
of
Control
collec9vely
decouple
applica9on
code
from
the
deployment
environment.

  17. 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

  18. 18. Simula3ng
a
Produc3on
Environment

  19. 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. 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. 21. Step
3
•  Use
open
source
replacements
for
 environment‐specific
components
 –  preferably
configurable
via
Spring
 ApplicaOonContext
 –  typically
in‐memory
(a.k.a.,
embedded
mode)

  22. 22. Open
Source
Frameworks
for
 Embedded
Use

  23. 23. Database
•  Use
an
in‐memory
database
such
as
 –  HSQL,
H2,
or
Derby
•  Spring
3.0
provides
explicit
support
for
 –  Embedded
databases
 –  PopulaOng
exisOng
databases

  24. 24. Embedded
Database
in
XML
<jdbc:embedded-database id="dataSource" type="H2"> <jdbc:script location="classpath:/my-schema.sql" /> <jdbc:script location="classpath:/my-data.sql" /> </jdbc:embedded-database> Or simply… <jdbc:embedded-database id="dataSource" />

  25. 25. Embedded
Database
in
Code
private EmbeddedDatabase db; @Before public void launchDatabase() { db = new EmbeddedDatabaseBuilder()
 .addDefaultScripts()
 .build(); } // tests … @After public void shutdownDatabase(){ db.shutdown(); }
  26. 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. 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

  28. 28. AcOveMQ
Spring
ConfiguraOon
<bean id="connectionFactory" class= "org.apache.activemq.spring.ActiveMQConnectionFactory” p:brokerURL="vm://localhost?broker.persistent=false" /> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate" p:connectionFactory-ref="connectionFactory" />

  29. 29. SMTP
Server
•  Use
Dumbsters
SimpleSmtpServer
 –  Configurable
port
number
 –  Tracks
all
mails
sent

 –  Provides
methods
for
retrieving
 •  Number
of
mails
sent
 •  Individual
mails
 •  Mail
headers
 •  Mail
body

  30. 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();
  31. 31. AbstractEmailSenderTest
(2/2)
protected void assertNumEmailsSent(SimpleSmtpServer server, int expected) { assertEquals("Verifying number of e-mails sent.”, expected, server.getReceivedEmailSize()); } protected void assertEmailHeaderValue(SmtpMessage email, String header, String expected) { assertEquals(expected, email.getHeaderValue(header)); } protected void assertEmailBodyContains(SmtpMessage email, String expected) { assertTrue(email.getBody().contains(expected)); }
  32. 32. PlainEmailSenderTest
(1/2)
@ContextConfiguration("/applicationContext.xml") public class PlainEmailSenderTest extends AbstractEmailSenderTest { @Autowired private PlainEmailSenderImpl plainEmailSender; @Override protected int getSmtpPort() { return 62525; }
  33. 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. 34. FTP
Server
•  Use
MockFtpServers
 –  FakeFtpServer
 •  Virtual
or
in‐memory
file
system
 •  User
accounts
and
permissions
 –  StubFtpServer
 •  Low‐level
FTP
server
commands

  35. 35. Servlet
Container
•  Use
Jeny
or
Tomcat
in
embedded
mode
•  Configure
Jeny
with
Maven
and
execute
the
 jeny:run
goal

  36. 36. ConfiguraOon
Tips
•  Externalize
connecOon
se_ngs
in
Java
 ProperOes
files
•  Define
different
ProperOes
files
for
producOon
 and
tesOng
•  Use
Springs
PropertyPlaceholderConfigurer
or
 <context:property‐placeholder>
for
property
 replacement

  37. 37. Avoid
Hostname
&
Port
Collisions
•  Pay
special
anenOon
to
hostnames
and
ports
 –  SMTP
 –  FTP
 –  Servlet
container
•  Consider
using
something
like
Springs
 FreePortScanner

  38. 38. Demo
Embedded
HSQL
database
with
Spring’s
<jdbc
/>
namespace
HibernateEventRepositoryTests

  39. 39. Demo
JMS
with
an
in‐memory
AcOveMQ
message
broker
JmsNamespaceTest

  40. 40. Demo
Email
with
Dumbster’s
SimpleSmtpServer
PlainEmailSenderTest

  41. 41. Demo
Embedded
Jeny
Servlet
container
AbstractJeKyTest

  42. 42. Further
Resources
•  HSQLDB
 –  hnp://hsqldb.org
•  H2
 –  hnp://www.h2database.com
•  AcOveMQ
 –  hnp://acOvemq.apache.org
•  Dumbster
 –  hnp://quintanaso+.com/dumbster
•  MockFtpServer
 –  hnp://mock+pserver.sourceforge.net
•  Jeny
 –  hnp://jeny.codehaus.org
•  Tomcat
 –  hnp://tomcat.apache.org

  43. 43. Q&A
Sam
Brannen
sam.brannen
[at]
swi+mind
[dot]
com
hnp://www.swi+mind.com
hnp://twiner.com/sam_brannen
“Spring
in
a
Nutshell” hnp://oreilly.com/catalog/9780596801946
 available
from
O’Reilly
in
2011


×