the mockcentral server
The getting started and examples sections of this documentation provide an introduction to the general concepts and basics of using the MockCentralServer and the javadoc and source are available for more detailed information, so this page focuses on practical usage issues.
requirements
MockCentralServer requires java version 1.6 or greater and that the following libraries to be on the classpath: commons-beanutils, commons-collections, commons-digester, commons-logging and mockobjects-core. These libraries are freely and widely available from many sources on the web and for convenience they have also been included in the main (non-source) zip and tar.gz distributions.
It is also required that you have a log4j.properties file on your classpath when running your tests.
initialization
The server requires initialization with either an
InputStream, File or String for
obtaining the xml document used to build fixtures and mock objects.
In addition, it can be supplied with a HashMap
containing runtime variables for use in tests and/or a boolean
value indicating whether proxies should be bound in a
NamingContext created by the application. The server's
init method is thus heavily overloaded to handle all
combinations of these parameters. For details, check out the
javadoc.
the mockcentral testing context
The MockCentralTestingContext can be used to
automatically bind proxies for use by classes that perform JNDI
lookups invoked in your tests. It's basically a simple Map-based
implementation of the javax.naming.Context interface.
The MockCentralServer (if initialized as described above) will
create an instance of this class which will be assigned as the
default for the InitialContextFactory contained in the
system's javax.naming.spi.NamingManager. You can use
the server's bindFixtureProxies(String) method to load
proxy objects into the context at any point in your test cases.
logging
At INFO level, the MockCentralServer application will log messages for the following events:
- the server is initialized with a variables map.
- a fixture is created during initialization.
- a fixture's proxies are loaded into the context during test execution.
At DEBUG level, MockCentralServer application will log messages for the following events:
- a MockObjectSetup is created during initialization.
- a JNDI name is added to a MockObjectSetup during initialization.
- a method expectation is added to a MockObjectSetup during initialization.
- a proxy is bound into the context during test execution.
- a proxy is looked up in the context during test execution.
By tracing this logging output you can see exactly what the server is expecting to happen and what calls your tests make relating to bindings and lookups. Here are excerpts from the DEBUG-level output generated when running the test in the jms example:
INFO [main] (MockCentralServer.java:343) adding runtime variables map: {randomOrderTotal=7}
INFO [main] (Fixture.java:118) creating Fixture jms_example: defines an OrderTotalProvider mock.
INFO [main] (Fixture.java:118) creating Fixture totalOrdersMessager_message_sent_ok: defines mocks used for testing message-sending success.
INFO [main] (Fixture.java:118) creating Fixture totalOrdersMessager_message_sent_failed: defines mocks used for testing message-sending failure.
DEBUG [main] (MockObjectSetup.java:186) initializing mock object: jms_example.orderTotalProvider (com.xyz.jms.OrderTotalProvider)
DEBUG [main] (MockObjectSetup.java:302) (orderTotalProvider) added matchAndReturn to method "getTotalOrders" with no params, expected return value set to randomOrderTotal
DEBUG [main] (MockObjectSetup.java:186) initializing mock object: totalOrdersMessager_message_sent_ok.queue (javax.jms.Queue)
DEBUG [main] (MockObjectSetup.java:193) added jndi name for mock object: queue/logEntries
...
INFO [main] (MockCentralServer.java:400) loading fixture totalOrdersMessager_message_sent_ok
DEBUG [main] (MockCentralTestingContext.java:113) clearing all bindings
DEBUG [main] (MockCentralTestingContext.java:75) binding object to queue/logEntries
DEBUG [main] (MockCentralTestingContext.java:75) binding object to ConnectionFactory
DEBUG [main] (MockCentralTestingContext.java:104) returning object bound to ConnectionFactory
DEBUG [main] (MockCentralTestingContext.java:104) returning object bound to queue/logEntries
click here to see a sample
log4j.properties file for use with MockCentral.
validation and thrown exceptions
For the server to work properly, the configuration files must be
well-formed xml and conform to the MockCentral
config file DTD. During initialization, the server will
validate all data defined for method expectation parameters and
expected results to assure that proper values can be created using
the specified <valueType>, <valueClassName> and/or
<value> xml elements. A
MockCentralServerException will be thrown, for
example, if the xml indicates that a boolean value type should be
created with a value of '3' or a new instance of a class unknown to
the server (not on the classpath) should be assigned as a return
value. References within method expectations to other mock objects
that are not defined in the configuration file will result in a
UnknownProxyException being thrown during
initialization. Likewise, circular mock object references and
fixture imports are tested for. At test execution time, an
UnknownProxyException will also be thrown for any
unkown proxies you attempt to look up within your test code, say
for object creation or verifications.
some strategies for use
Pull initialization code up to test case superclasses.
Use test case superclasses or TestSetup classes to
perform server initialization and other common setup tasks (like
creating references to proxies obtained from the server) that are
required by a suite of tests. Sure, this general testing technique
is an obvious one, but it's worth mentioning.
Use the 'anyParams' declaration in method expectations to
streamline setup. When you need mock object method expectations
that will be called repeatedly but with varying parameters and
don't require each invocation to return distinct results, add an
anyParams xml element to your method expectation (the
MockCentralEditor will do this for you with a button-click). This
will result in the server creating an
AnyConstraintMatcher for the expectation which can
handle any input, saving you time and effort.
One config file or many? You can create a single large configuration file for all of your tests (which can facilitate organization and reuse, but may be overkill for running individual tests that don't need every defined mock object and may become unwieldy), or you can create multiple, more finely-grained configuration files (which may be easier to manage and speed the server along, but can require changes to many files if you alter the method signature of one of the interfaces in your domain code). Which approach to use depends on the circumstances, but note that the copy and paste functions available in the MockCentralEditor application can help greatly when you use multiple config files.
Parallel fixtures and fixture importing: Testing how a Method behaves with various input and testing Exception-handling code can require defining multiple mock objects for the different scenarios. Use fixtures to group the mock objects pertaining to each condition you want to test, and abstract common mock objects to a fixture that these can import using the "importFixture" declaration. That way you can easily set up "parallel" fixtures as needed to test your code.
