DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Wicket Tutorial Series: Writing the Tests

Wicket Tutorial Series: Writing the Tests

Johan Edstrom user avatar by
Johan Edstrom
·
Mar. 11, 09 · Interview
Like (0)
Save
Tweet
Share
12.14K Views

Join the DZone community and get the full member experience.

Join For Free

In the course of building an application, whether it due to shortened timelines, lack of process, or laziness, tests become an afterthought. Tests often are added when problems are found, or to root out bugs that were not found during early phases.

This article, day 2 of our project, will show how to write a solid baseline for your application with tests as the strong foundation. Our first meetings laid down the scope and direction we wanted achieved for this short project. We had a clear sense of the problem we wanted to solve, as well as the basic components we were going to implement.

In testing code there are several cycles commonly used in the enterprise community. We will start our testing tutorial by talking about mocks.

Mocks

The Wikipedia page on Mock object describes them simply:

In object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways

In Java, utilizing Mock objects generally requires the usage of interfaces. The interfaces are hopefully something that evolved from initial design discussions, and become the basis for the expected functions and behavior.

The tool we use to build the Mocks is EasyMock and JUnit for unit tests. In your search for the ultimate testing tool, I’d strongly encourage you to try out other tools such as TestNG and JMock.

The longest running unit-testing tool in the Java world is definitely JUnit. If you’d like to read up on Test Driven Development and each of the concepts outlined here in more detail, Test Driven Development by Example is a brilliant book written by Kent Beck on the topic. Test Driven Development stands alone in the Agile theory as the most effective value preached, especially when done early, and done comprehensively.

We have a few interfaces now, which came of initial discussion about how we imagine a pastebin functioning, so what is the next step? And how can testing help us?

Here is the primary service interface:

public interface PasteService {
	List getLatestItems(String clientToken, int count, boolean threaded) throws InvalidClientException;
	PasteItem getItem(String clientToken, long id) throws InvalidClientException;
	PasteItem findPrivateItem(String clientToken, String privateToken) throws InvalidClientException;
	List findItemsByLanguage(String clientToken, LanguageType languageType, int count, boolean threaded) throws InvalidClientException;
	long createItem(String clientToken, PasteItem item) throws InvalidClientException;
	long createReplyItem(String clientToken, PasteItem item, long parentId) throws InvalidClientException, ParentNotFoundException;
	List getItemsForUser(String clientToken, String userToken) throws InvalidClientException;
	PasteStats getStats(String clientToken) throws InvalidClientException;
}

 

 

This is the first step in the design, we now have something describing the desired functionality, so we will start by mocking these interfaces.

EasyMock is a handy tool for this, so we simply add the necessary bits and pieces to our pom file and reload the project to get the correct dependencies:

<dependency>
 <groupId>org.easymock</groupId>
 <artifactId>easymock</artifactId>
 <version>2.4</version>
 </dependency>
<dependency>
 <groupId>org.easymock</groupId>
 <artifactId>easymockclassextension</artifactId>
 <version>2.4</version>
 </dependency>

We’ve also made some changes to the initial POM that we created to pull in JUnit version 4.5. Newer versions of JUnit are backwards compatible and add enhancements to your testing such as annotations.

For our first mocks, we start off with extending JUnit’s default TestCase. We add in some convenience methods to help us return a mock Dao and a mock Service.

	private PasteItemDao dao;
	private PasteService svc;
	@Test
	public void testMocks() {
		dao = getPasteItemDao();
	 	assertNotNull(getPasteItemDao());
	 	svc = getPasteService();
	 	assertNotNull(getPasteService());
	}
	@Test
	public void testGetLatestItems() throws Exception {
		svc = getPasteService();
		assertNotNull(getPasteService());
		expect(svc.getLatestItems("CLIENT", 10, false)).andReturn(getPastes(10, LanguageType.PASCAL, false));
		replay(svc);
		List returnedList = svc.getLatestItems("CLIENT", 10, false);
		verify(svc);
		assertEquals(10, returnedList.size());
	}

 

What we are doing here is essentially describing the calls we expect, we replay and call the mocked service and finally we verify and assert that the results are as expected.

While this may seem quite obvious, this will help us in comparing what an implementation will have to return, that the code has coverage and the mocks of these classes actually behave as expected. Once we have full mock coverage we can start implementing the code, and keep looping back to our tests to verify that things work as expected.

Integration and Implementation Tests

Once we have a working implementation, covered by our mock tests for expected behavior, the next step to consider are integration tests. Integration tests involve a more complete test involving third party components such as a database or complex services. The focus here is to track down potential errors in our project e.g. configuration files, Dao mapping and entity problems, etc. The tool we consider well thought out and best of breed would help us setup a complete testbed, to include an in-memory database.

Unitils brings together several common tools used separately into a cohesive integration testing framework. It provides the ability to run a Spring context and an in-memory database which we can use to perform full life-cycle tests on all components. These tools let us write tests that will verify our applications behaviour in a real life situation. The value here can be seen later in the project, as it will continue to be referenced throughout the lifecycle of our project. We can use them to hunt down possible bugs, add features without worry of breaking other pieces of our application, or simply maintaining and refactoring the codebase. Yet another benefit is hidden, for it helps new developers on the project understand how everything ties together without the need for a separate, distant, and possibly rarely updated document.

We hunt down our applications Spring configuration file “applicationContext.xml” and make a copy of it and place it in “src/test/resources”. In addition we add a secondary configuration file “applicationContext-test.xml” that overrides the default datasource and supplies a Unitils datasource.

applicationContext-test.xml

<?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:tx="http://www.springframework.org/schema/tx"
	   xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
   <bean id="dataSource" class="org.unitils.database.UnitilsDataSourceFactoryBean"/>
</beans>

 

 

We then add a file “unitils.properties” where we define how unitils is supposed to behave.

# Properties for the PropertiesDataSourceFactory
database.driverClassName=org.hsqldb.jdbcDriver

database.url=jdbc:hsqldb:mem:mysticpaste-test
database.userName=sa
database.password=

# This property specifies the underlying DBMS implementation. Supported values are 'oracle', 'db2', 'mysql', 'hsqldb' and 'postgresql'.
# The value of this property defines which vendor specific implementations of DbSupport and ConstraintsDisabler are chosen.
database.dialect=hsqldb

## This property specifies the database schema that is used. This schema name is used to qualify all tables when (amongst
# others) clearing / dropping tables / inserting test data.
# NOTE: schema name is case sensitive
database.schemaName=mysticpaste
dbMaintainer.generateDTD.enabled=TRUE
# DbUnit database DTD file path
dtdGenerator.dtd.filename=src/resources/test.dtd

This file will now allow us to move on to an implementation we start with an AbstractBaseTest where we extend a Unitils class called UnitilsJUnit4.

public class AbstractIntegrationTest extends UnitilsJUnit4 {
	@SpringApplicationContext({"applicationContext.xml", "applicationContext-test.xml"})
	private ApplicationContext applicationContext;
	/**
		* Method testDoNothing ...
		*/
	   //This is to keep maven surefire quiet.
		@Test
	   public void testDoNothing() {
		   //Nothing
	   }
}

 

If you run the test, you will see in the logging output a complete invocation of the spring context, database setup and verification of mapped entities, pretty nifty for an empty test!

We can now move on to testing the actual implementations provided with a full cycle environment.

As we are using Unitils and its Spring utilities we also have handy annotations for injecting our real daos and their implementations into our tests.

Our final test-class that will completely test our environment looks as follows:

public class PasteServiceIntegrationTest extends AbstractIntegrationTest {
	@SpringBeanByType
	private PasteService svc;
	@SpringBeanByType
	private PasteItemDao dao;
	// We start with verifying that the DB is correctly setup.
	@Test
	public void testMapping() {
		HibernateUnitils.assertMappingWithDatabaseConsistent();
	}
	@Test
	public void testGetCurrentCount() {
		PasteItem paste = new PasteItem();
		paste.setContent("TEST-DATA");
		paste.setUserToken("USER");
		paste.setClientToken("CLIENT");
		try {
			svc.createItem("CLIENT", paste);
			assertTrue(svc.getItemsForUser("CLIENT", "USER").size() == 1);
		} catch (InvalidClientException e) {
			e.printStackTrace();  //TODO
		}
	}
	@Test
	public void testCreateAndRetrieve() throws InvalidClientException {
		PasteItem paste = new PasteItem();
		paste.setContent("TEST-DATA");
		paste.setUserToken("USER");
		paste.setClientToken("CLIENT");
		Long id = svc.createItem("CLIENT", paste);
		System.out.println(id);
		PasteItem item2 = svc.getItem("CLIENT", id);
		assertEquals(item2.getClientToken(), paste.getClientToken());
	}
}

Voila! We have a complete life cycle test.  These tests of course run somewhat slower than mocks. As tools and aids to rapid development they are quite valuable and will help find elusive bugs and problematic issues.

Mystic Coders, LLC has been coding web magic since 2000. Mystic is a full-service Development Agency specializing in Enterprise development with Java. They are usually involved in developing enterprise-grade software for companies large and small, and have experience working in diverse industries, including b2b, b2c, and government-based projects. Mystic has done work with large companies such as LeapFrog, Nestlé, Harrah's Entertainment and the Los Angeles Conventions & Visitor's Bureau, among others. Andrew Lombardi, CTO of Mystic, is available for speaking engagements.


For more about Mystic, check us out at http://www.mysticcoders.com 

unit test Database Test-driven development application Implementation Interface (computing) JUnit Object (computer science) In-memory database

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • DevOps for Developers: Continuous Integration, GitHub Actions, and Sonar Cloud
  • Top 10 Best Practices for Web Application Testing
  • How To Build a Spring Boot GraalVM Image
  • Secure APIs: Best Practices and Measures

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: