The REST Services tests and their test base are for testing the REST clients and services configuration, as well as their calls into the service layer. There is an in memory database and controllers are loaded in an embedded jetty server.
There are actually two main Spring contexts. One is the standard test context that just loads the REST clients and a properties file to configure the path to the REST APIs and any other client configuration information.
The other context is loaded in the EmbeddedJetty
bean.
It takes the list of Spring configuration files and loads them in a parent context,
then a servlet child context is created. It also registers
the Spring Security filter with the servlet handler.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <import resource="classpath*:/META-INF/spring/client/**/*-context.xml"/> <util:properties id="restProperties" location="org/springbyexample/contact/web/service/ws.properties" /> <bean class="org.springbyexample.web.service.EmbeddedJetty"> <constructor-arg> <list> <value>/embedded-jetty-context.xml</value> <value>/META-INF/spring/security/**/*-context.xml</value> <value>/META-INF/spring/marshaller/**/*-context.xml</value> <value>/META-INF/spring/db/**/*-context.xml</value> <value>/META-INF/spring/services/**/*-context.xml</value> <value>/META-INF/spring/mvc/**/*-context.xml</value> <value>/mock-web-security-context.xml</value> </list> </constructor-arg> </bean> </beans>
The AbstractRestControllerTest
sets up the shared Spring test configuration,
and before each test resets the DB by re-initializing the schema and clearing the JPA entity manager cache.
Example 7. AbstractRestControllerTest
@ContextConfiguration({ "classpath:/org/springbyexample/contact/web/service/rest-controller-test-context.xml" }) public abstract class AbstractRestControllerTest extends AbstractProfileTest { final Logger logger = LoggerFactory.getLogger(AbstractRestControllerTest.class); @Autowired private EmbeddedJetty embeddedJetty; /** * Reset the DB before each test. */ protected void doInit() { reset(); } /** * Reset the database and entity manager cache. */ protected void reset() { resetSchema(); resetCache(); logger.info("DB schema and entity manager cache reset."); } /** * Resets DB schema. */ private void resetSchema() { ApplicationContext ctx = embeddedJetty.getApplicationContext(); DataSource dataSource = ctx.getBean(DataSource.class); @SuppressWarnings("unchecked") List<Resource> databaseScripts = (List<Resource>) ctx.getBean("databaseScriptsList"); Connection con = null; ResourceDatabasePopulator resourceDatabasePopulator = new ResourceDatabasePopulator(); try { con = dataSource.getConnection(); resourceDatabasePopulator.setScripts(databaseScripts.toArray(new Resource[0])); resourceDatabasePopulator.populate(con); } catch (SQLException e) { logger.error(e.getMessage(), e); } finally { try { con.close(); } catch (Exception e) {} } } /** * Reset cache. */ private void resetCache() { ApplicationContext ctx = embeddedJetty.getApplicationContext(); EntityManagerFactory entityManagerFactory = ctx.getBean(EntityManagerFactory.class); Cache cache = entityManagerFactory.getCache(); if (cache != null) { cache.evictAll(); } } }
The AbstractPersistenceFindControllerTest
provides an abstract base
for testing a PersistenceFindMarshallingService
.
Example 8. AbstractPersistenceFindControllerTest
public abstract class AbstractPersistenceFindControllerTest<R extends EntityResponseResult, FR extends EntityFindResponseResult, S extends PkEntityBase> extends AbstractRestControllerTest { protected final Logger logger = LoggerFactory.getLogger(getClass()); protected final int id; protected final long expectedCount; public AbstractPersistenceFindControllerTest(int id, long expectedCount) { this.id = id; this.expectedCount = expectedCount; } /** * Gets find client. */ protected abstract PersistenceFindMarshallingService<R, FR> getFindClient(); /** * Tests if record is valid. */ protected void verifyRecord(S record) { verifyRecord(record, false); } /** * Tests if record is valid and can specify whether or not it was a save. */ protected abstract void verifyRecord(S record, boolean save); @Test @SuppressWarnings("unchecked") public void testFindById() { R response = getFindClient().findById(id); assertNotNull("Response is null.", response); verifyRecord((S) response.getResults()); } @Test @SuppressWarnings("unchecked") public void testPaginatedFind() { int page = 0; int pageSize = 2; FR response = getFindClient().find(page, pageSize); assertNotNull("Response is null.", response); assertEquals("count", expectedCount, response.getCount()); assertNotNull("Response results is null.", response.getResults()); verifyRecord((S) response.getResults().get(0)); } @Test @SuppressWarnings("unchecked") public void testFind() { FR response = getFindClient().find(); assertNotNull("Response is null.", response); assertEquals("count", expectedCount, response.getCount()); assertNotNull("Response results is null.", response.getResults()); verifyRecord((S) response.getResults().get(0)); } /** * Tests if audit info is valid. */ protected void verifyAuditInfo(DateTime lastUpdated, String lastUpdateUser, DateTime created, String createUser) { DateTime now = DateTime.now(); assertNotNull("'lastUpdated' is null", lastUpdated); assertNotNull("'lastUpdateUser' is null", lastUpdateUser); assertNotNull("'created' is null", created); assertNotNull("'createUser' is null", createUser); assertTrue("'lastUpdated' should be before now.", (lastUpdated.isBefore(now))); assertTrue("'created' should be before now.", (created.isBefore(now))); } }
The AbstractPersistenceControllerTest
provides an abstract base
for testing a PersistenceMarshallingService
.
Example 9. AbstractPersistenceControllerTest
public abstract class AbstractPersistenceControllerTest<R extends EntityResponseResult, FR extends EntityFindResponseResult, S extends PkEntityBase> extends AbstractPersistenceFindControllerTest<R, FR, S> { protected final Logger logger = LoggerFactory.getLogger(getClass()); public AbstractPersistenceControllerTest(int id, long expectedCount) { super(id, expectedCount); } /** * Gets find client. */ protected PersistenceFindMarshallingService<R, FR> getFindClient() { return getClient(); } /** * Gets client. */ protected abstract PersistenceMarshallingService<R, FR, S> getClient(); /** * Create save request. */ protected abstract S createSaveRequest(); @Test @SuppressWarnings("unchecked") public void testSave() { S request = createSaveRequest(); R response = getClient().save(request); assertNotNull("Response is null.", response); verifyRecord((S) response.getResults(), true); int expectedCount = 1; assertEquals("messageList.size", expectedCount, response.getMessageList().size()); logger.info(response.getMessageList().get(0).getMessage()); } @Test public void testDeletePk() { ResponseResult response = getClient().delete(id); assertNotNull("Response is null.", response); int expectedCount = 1; assertEquals("messageList.size", expectedCount, response.getMessageList().size()); logger.info(response.getMessageList().get(0).getMessage()); } /** * Tests if primary key is valid. */ protected void verifyPrimaryKey(int id, boolean save) { if (!save) { assertEquals("'id'", id, this.id); } else { assertTrue("Primary key should be greater than zero.", (id > 0)); } } }
Since all of the main testing for the PersistenceMarshallingService
client
is in the parent classes, just the constructor and a few methods need to be implemented.
The constructor takes the primary key used by find tests and the expected count for retrieving all records.
The methods implemented are getClient()
to return this test's client,
the request to be saved, and a verification method.
Example 10. PersonControllerTest
public class PersonControllerTest extends AbstractPersistenceControllerTest<PersonResponse, PersonFindResponse, Person> { @Autowired private PersonClient client = null; public PersonControllerTest() { super(1, 3); } @Override protected PersistenceMarshallingService<PersonResponse, PersonFindResponse, Person> getClient() { return client; } @Override protected Person createSaveRequest() { return new Person().withFirstName(FIRST_NAME).withLastName(LAST_NAME); } @Override protected void verifyRecord(Person record, boolean save) { assertNotNull("Result is null.", record); verifyPrimaryKey(record.getId(), save); assertEquals("'firstName'", FIRST_NAME, record.getFirstName()); assertEquals("'lastName'", LAST_NAME, record.getLastName()); verifyAuditInfo(record.getLastUpdated(), record.getLastName(), record.getCreated(), record.getCreateUser()); logger.debug("id=" + record.getId() + " firstName=" + record.getFirstName() + " lastName=" + record.getLastName() + " lastUpdated=" + record.getLastUpdated() + " lastUpdateUser=" + record.getLastUpdateUser() + " created=" + record.getCreated() + " createUser=" + record.getCreateUser()); } }