This is the documentation for MockEJB 0.5. APIs and capabilities of MockEJB 0.6
have changed pretty drastically, especially in regard to interceptors implementation.
This documentation will be updated soon.
Overview of MockEJB
How to Run MockEJB Tests Inside the
and Deploying Mock EJBs
Support for Interceptors
Using Transactions with MockEJB
Please start by reviewing MockEJB examples.
MockEJB uses dynamic proxies to create objects
implementing Home and business (remote or local) interfaces. When the
MockContainer.deploy(), MockEJB creates
proxy implementing the Home interface and binds it to the JNDI context
Context.rebind() call. MockEJB also creates an
instance of the
and returns it to the client.
Client can then look up the Home proxy in JNDI and call
At this point, MockEJB creates dynamic proxy to the business interface
and returns it to the client.
Every call to the Home or business interface method goes
through the list (stack)
of interceptors. Clients have full control
over this call chain through the
returned by the
MockContainer.deploy(), e. g., they can
add or delete the interceptors
or change their behavior.
MockEJB comes with in-memory JNDI implementation
MockContext is ideal for testing since it does
not persist objects. It means that any change to JNDI disappears after
the test case completes. You can also plug in a different JNDI
provider, for example you can use JNDI provider of your application
In order to use
MockContext, you need to
as the initial context factory. The easiest way to do it is to invoke
method at the beginning of your test (in
This method sets
system properties. The second property is required to be able to handle
"java:comp" context. More details on the URL-prefixed contexts can be
MockContext does not scope
"java:comp/env" context to the bean where
it was created. In other words, you can bind
any object to this context, however its name will be global, therefore
it should be unique within your test.
changes system properties, it is a good idea to restore the original
state of the environment in
tearDown(). All you need to
do is to call
This will allow
your test class to run inside the container without affecting test
classes that might potentially run after it. Otherwise, you'll need to
bounce the JVM of the application server.
Before you can run your test class, you have to populate
its JNDI tree.
To do this, you need to figure out what objects your EJBs (or any other
code that is
part of the test case) expect to see in JNDI. Then instantiate and bind
For example, if your EJB needs JDBC support, you can instantiate and
DataSource implementation that comes with your
JDBC driver. If you put this logic in the
setUp method of
your class, you'll have to use
setUp will run multiple times per test class.
MockContext is capable of looking up
objects in a delegate JNDI context.
This means that
MockContext first searches its local JNDI
tree and if the object is not found there, it will look in the JNDI
tree of the delegate context.
This is convenient when you want to rely on the resources deployed into
server, such as data sources and connection factories. So, in this
case, application server acts as a delegate context. This approach
gives you the alternative to manually pre-populating
with all required resources.
Note that while using delegate context increases the
dependency of the test class on the external resource, such as the
application server, it preserves most of the benefits of the mock
objects approach. You can still run your EJBs outside of the
container and avoid having to redeploy them every time you change the
code. Application server is this case can be viewed as yet another
service provided by the OS
where your test class runs. To support this notion, you need to make
sure that the application server always runs in the background, e.g.,
you can start it as part of the startup sequence when you login.
Another important delegate context usage is the support
for mock EJBs when you run your tests inside the container. MockEJB
framework deploys mock EJBs using
all tested (non-mock) EJBs are bound in the JNDI tree of the
application server (deployed by
the regular means). See "Mock EJBs" section for
In order to setup the delegate context, you need to call
method. If your test runs inside the application server, you can simply
pass the environment returned by the current context (provided by the
Of course, you should do it before you call
call changes the JNDI environment.
Outside of the container, at the very minimum you need
to pass the initial context factory and the provider URL of the remote
Running EJB tests locally using MockEJB is not a
substitute for in-container
testing with your application server. Local tests are extremely
convenient for ongoing development work, but you still have to run the
in-container tests on a regular basis.
MockEJB allows you to run the same test class inside and
outside of the container with
minimal modifications. However, you might also want to have a
completely different set of tests for the in-container testing. These
tests may deal more with running "end-to-end" integration scenarios
than with testing individual EJBs. The approach for in-container
testing depends mostly on the complexity of your project and, to some
extend, the organization of the development team.
You should also keep in mind that MockEJB does not
support EJB deployment descriptors. So, to test the deployable EJBs,
developers should run in-container tests. If the same group of
developers is responsible for developing and deploying the code,
running the same tests inside and outside of the container might be
MockEJB integrates with the Cactus framework for
MockEJB allows you to switch between Cactus and local MockEJB testing
modes at any time. This is accomplished by using
class as a superclass for your test classes. By default the test class
runs locally exactly the same way it would if it extended
directly. If the
mockejb.cactus.mode system property is
to run the test class.
ServletTestCase then runs the
tests on the application server (assuming the test class and all tested
EJBs are deployed to this server). Alternatively, a test class can
method and use a different mechanism for determining which mode to use
when it runs.
There might be differences in the setup code for your
test class depending on where it runs. For example, if you run the test
class locally, you may need to setup the data source by directly
instantiating a JDBC driver-provided class and binding it
to JNDI. When the test runs inside the container, you may want to rely
on the data source
pre-configured in the application server.
true when the test runs inside the
container under the Cactus framework. So the code that sets up the data
source for out of container testing
should be enclosed into
if (!isRunningOnServer()) block.
The alternative approach is to use the inheritance. In
this case, your test class should only have the code required to run it
on the server. Its subclass should have the additional
setup code needed for running it locally. Both classes should override
Mock EJBs (i.e., mock EJB implementation classes, not to
be confused with MockEJB framework) do not have the real business
Instead, their logic is provided by the developer of a test class. That
way you can isolate EJBs under test from the rest of the application.
Suppose you've implemented
BarBean. You also developed
FooBeanTest class to unit test
In this case, you don't want
FooBean to call the real
BarBean implementation might change which will
require you to update
may call other EJBs or use some resources provided by the application
server, which will complicate the setup code of your test class and
make the test class logic more brittle. The classic example is the
dependency on the entity beans and the database.
MockEJB framework allows you to replace the
business logic with the mock implementation that behaves exactly the
way expected by the test class. Its methods could return hardcoded
data, provide "stubs" for database operations and test the passed
parameters. The implementation class of a mock EJB can be defined as
the nested class of the test class. See
FundamentalsTest example for more details. You can also use easymock
or mockobjects frameworks.
Note that to implement a mock EJB, you only need to
provide the "bean" (implementation) class. Home and business interfaces
are shared with the "non-mock" EJB.
Outside of the container, mock EJBs are deployed the
same way with other EJBs using
Inside the container, mock EJBs rely on the ability of
to access delegate JNDI context. More specifically, Mock EJBs are
MockContainer.deploy() which puts them
Non-mock EJBs are deployed by the application server which binds them
to its own JNDI tree. JNDI context of the application server should be
set as the delegate
first searches its
local context, so mock EJBs are always found first, even if the EJB
with the same name was already deployed by the application server.
If you want to run the same test class inside and
outside of the container, enclose
for tested ("non-mock") EJBs in
if (! isRunningOnServer() )
In this case, only mock EJBs will be deployed by the
whereas EJBs under test will be deployed by the application server.
Packaging of mock EJBs for in-container testing requires
understanding of the application server's classloader hierarchy.
The usual practice with Cactus is to package test classes with the
Cactus web application. This approach, however, does not work for the
mock EJB implementation class. Normally, Web application classloader is
the child of EJB classloader, so the classes packaged with the web
application are not visible to EJBs.
So, Mock EJB implementation class should either be packaged with the
tested (calling) EJB classes or in another jar which is part of the
classpath of the tested EJB jar.
MockEJB allows you to specify a chain (stack) of custom
objects that handle (intercept) EJB calls.
Interceptors are extremely powerful and can be used for a variety of
tasks. For example, interceptor can execute "asserts" for input
return result of a method called indirectly from the test (e.g., test
calls EJB A, EJB A calls EJB B).
In MockEJB interceptors implement
interface. Internally, interceptors are controlled by the
ObjectInvoker calls the interceptors according to
their order in the
java.util.List which is part of
constructor. Each interceptor must do a callback to
ObjectInvoker class also provides the
mechanism to access
javax.ejb.MessageDrivenContext of the invoked EJB.
You can specify the list of interceptors explicitly in
the code of your test class.
testCustomInterceptor() method of
FundamentalsTest example for more details.
MockEJB comes bundled with two system interceptors:
MockEJB always implicitly sets
ExceptionHandler at the
head of the interceptor list.
responsible for exception handling
according to the EJB specification.
always follows the
ExceptionHandler in the interceptor
list (see "Using Tranactions" section).
Custom interceptors can be added using
MockEjbObject.getInterceptorList() returns the
linked list of interceptors which you can
manipulate. This includes full access to system interceptors.
MockEJB also provides
Once added to the interceptor list, it stores the information about
method calls to the intercepted object. Later on, this information can
be queried by the test class. The structure of the preserved
information is defined by the
InvocationRecorder can be selectively added to
the interceptor list of the EJBs you want to
check. In many cases,
InvocationRecorder provides a
convenient alternative to the
MockEJB supports container-managed transactions using
interceptor. MockEJB always puts this interceptor on the call chain
ExceptionHandler. By default, the transaction
policy is "Supports" in which case
does not do anything.
To set a different
transaction policy, call
method. You can dynamically specify transaction policy that you need
for different methods thus emulating EJB deployment descriptor
For the most advanced transaction support needs, you can
TransactionManager and override its
method. In this method you can selectively set the policies that you
need for different EJB methods.
TransactionManager relies on
object. This object must be available in JNDI tree (under
"javax.transaction.UserTransaction" key) except for "Supports" and
"NotSupported" policies. Alternatively, you can set
One way to obtain
is to use JTA service provided by your application server. To do that,
you need to call
to set the JNDI context of your application server as the delegate
context (as described in "Configuring JNDI"
Of course, in this case, all resources that you use within your
transactions (such as DataSource) should support JTA.
Another option is to use the mock objects approach. For
framework comes with the mock
TransactionManager supports all five
transaction policies. However, support for "RequiredNew" and
"NotSupported" has some limitations. Currently
is not able to suspend transactions, so it simply tries to call
in case of these policies. Most JTA implementations will throw the
exception in this case (since they don't support nested transactions).
MockEJB provides JMS implementation that allows you to
test what messages are sent and in what order.
There are two administrative tasks that must be
performed before conducting a test:
- create destinations (queues and/or topics) and bind
them in JNDI context
- create connection factories and bind them in JNDI
Destinations are created by instantiating
for queues, and
org.mockejb.jms.MockTopic for topics.
Connections are created by instantiating
for queue connections, and
for topic connections.
What messages are sent and in what order can be checked
by examining the corresponded queues and topics.
All JMS related classes reside in the package
MockEJB JMS implementation is compatible with JMS versions 1.02b and