Effective out-of-container
    Integration Testing

        Sam
Brannen

       Swi+mind
GmbH

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

Agenda

•    Background

•    Goals
of
IntegraOon
TesOng

•    The
Challenge

•    Proposed
SoluOon

•    DI
and
IoC
as
Enablers

•    SimulaOng
a
ProducOon
Environment

•    Spring
TestContext
Framework

•    Q&A

Background

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

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

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

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

Goals
of
Integra3on
Tes3ng

EffecOve
IntegraOon
TesOng

•    Fast

•    Repeatable

•    Automated

•    Easy
to
configure

•    Provide
good
code
coverage
of
end‐to‐end

     business
use
cases

Out‐of‐container

•  Zero
reliance
on
availability
of
external

   systems

•  Can
be
run
anywhere

   –  developer
workstaOon

   –  CI
server

•  Approximate
a
target
producOon
environment

The
Challenge

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?

Proposed
Solu3on

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

DI
and
IoC
as
Enablers

Dependency
Injec9on
and
Inversion
of
Control

collec9vely
decouple
applica9on
code
from
the

deployment
environment.

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

Simula3ng
a
Produc3on
Environment

Step
1

•  Ensure
your
applicaOon
configuraOon
can
be

   split
into:

  –  applicaOon‐specific
configuraOon

     •  business
logic

     •  service
layer,
repository
layer,
etc.

  –  environment‐specific
configuraOon

     •  infrastructure

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

Step
3

•  Use
open
source
replacements
for

   environment‐specific
components

  –  preferably
configurable
via
Spring

     ApplicaOonContext

  –  typically
in‐memory
(a.k.a.,
embedded
mode)

Open
Source
Frameworks
for

      Embedded
Use

Database

•  Use
an
in‐memory
database
such
as

  –  HSQL,
H2,
or
Derby

•  Spring
3.0
provides
explicit
support
for

  –  Embedded
databases

  –  PopulaOng
exisOng
databases

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" />

Embedded
Database
in
Code

private EmbeddedDatabase db;	
@Before public void launchDatabase() {	
   db = new EmbeddedDatabaseBuilder()

            .addDefaultScripts()

            .build();	
}	
// tests …	
@After public void shutdownDatabase()
{	
   db.shutdown();	
}
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>

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

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" />

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

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();
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));	
}
PlainEmailSenderTest
(1/2)

@ContextConfiguration("/applicationContext.xml")	
public class PlainEmailSenderTest extends 	
    AbstractEmailSenderTest {	

  @Autowired	
  private PlainEmailSenderImpl plainEmailSender;	

 @Override	
 protected int getSmtpPort() {	
    return 62525;	
 }
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");	
}
FTP
Server

•  Use
MockFtpServer's

  –  FakeFtpServer

     •  Virtual
or
in‐memory
file
system

     •  User
accounts
and
permissions

  –  StubFtpServer

     •  Low‐level
FTP
server
commands

Servlet
Container

•  Use
Jeny
or
Tomcat
in
embedded
mode

•  Configure
Jeny
with
Maven
and
execute
the

   jeny:run
goal

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

Avoid
Hostname
&
Port
Collisions

•  Pay
special
anenOon
to
hostnames
and
ports

  –  SMTP

  –  FTP

  –  Servlet
container

•  Consider
using
something
like
Spring's

   FreePortScanner

Demo

Embedded
HSQL
database
with

Spring’s
<jdbc
/>
namespace


HibernateEventRepositoryTests

Demo

JMS
with
an
in‐memory
AcOveMQ

message
broker


JmsNamespaceTest

Demo

Email
with
Dumbster’s

SimpleSmtpServer


PlainEmailSenderTest

Demo

Embedded
Jeny
Servlet
container


AbstractJeKyTest

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

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


Effective out-of-container Integration Testing