Fork me on GitHub

Test Tutorial

This tutorial looks at testing a WoOF application.

To focus on testing, the below simple application to add two numbers will be used.

TestHttpServer screen shot.

Tutorial Source

Furthermore, production quality testing would cover a lot more test scenarios than is covered in this tutorial. The additional scenarios, however, have been excluded for brevity. They would all follow a similar pattern as described by this tutorial.

Application code

The application being tested has one page.

<html>
	<body>
		<form action="#{add}">
			<p><input type="text" name="a" value="${a}" /> 
			+ <input type="text" name="b" value="${b}" /> 
			= ${result}</p>
			<input type="submit" value="add" />
		</form>
	</body>
</html>

With the backing logic class.

public class TemplateLogic {

	@Data
	@HttpParameters
	public static class Parameters implements Serializable {
		private String a;
		private String b;
		private String result;
	}

	public void add(Parameters parameters, Calculator calculator) {
		int a = Integer.parseInt(parameters.getA());
		int b = Integer.parseInt(parameters.getB());
		parameters.setResult(String.valueOf(calculator.plus(a, b)));
	}

	public Parameters getTemplateData(Parameters parameters) {
		return parameters;
	}

}

And injected dependency.

public class Calculator {

	public int plus(int a, int b) {
		return a + b;
	}
}

Unit Testing

The following demonstrates unit testing the template logic class. As the template logic class is a POJO (Plain Old Java Object), it is unit tested like any other Java class.

	@Test
	public void unitTest() {

		// Load the parameters
		Parameters parameters = new Parameters();
		parameters.setA("1");
		parameters.setB("2");
		assertNull(parameters.getResult(), "Shoud not have result");

		// Test
		TemplateLogic logic = new TemplateLogic();
		logic.add(parameters, new Calculator());
		assertEquals("3", parameters.getResult(), "Incorrect result");
	}

This is a simple application. More complex applications may be dependency injecting more complex objects such as a java.sql.Connection or javax.persistence.EntityManager. Again as the template logic is a POJO, any mocking framework can be used to mock these objects for use in testing.

System Testing

As OfficeFloor is a very light weight framework, it starts and stops fast enough to be run with the unit tests.

The following demonstrates using the mock WoOF server. This server executes very fast, as there is no socket communication. Requests are passed in memory to the server making it very fast for testing. This also has the benefit of avoiding port binding clashes on shared build servers.

	@RegisterExtension
	public final MockWoofServerExtension server = new MockWoofServerExtension();

	@Test
	public void systemTest() throws Exception {

		// Send request to add
		MockHttpResponse response = this.server
				.sendFollowRedirect(MockHttpServer.mockRequest("/template+add?a=1&b=2").method(HttpMethod.POST));
		assertEquals(200, response.getStatus().getStatusCode(), "Should be successful");

		// Ensure added the values
		String entity = response.getEntity(null);
		assertTrue(entity.contains("= 3"), "Should have added the values");
	}

JUnit 4 example:

	@Rule
	public final MockWoofServerRule server = new MockWoofServerRule(this);

	@Test
	public void systemTest() throws Exception {

		// Send request to add
		MockHttpResponse response = this.server
				.sendFollowRedirect(MockHttpServer.mockRequest("/template+add?a=1&b=2").method(HttpMethod.POST));
		assertEquals("Should be successful", 200, response.getStatus().getStatusCode());

		// Ensure added the values
		String entity = response.getEntity(null);
		assertTrue("Should have added the values", entity.contains("= 3"));
	}

Live HTTP Sockets

However, should you want to run WoOF listening on sockets, then use the following. Again this is fast enough to run with the unit tests, but is neglibly slower due to socket communication.

@ExtendWith(OfficeFloorExtension.class)
public class TemplateLogicCallingTest {

	@RegisterExtension
	public final HttpClientExtension client = new HttpClientExtension();

	@Test
	public void callingSystemTest() throws Exception {

		// Send request to add
		HttpResponse response = this.client.execute(new HttpPost(this.client.url("/template+add?a=1&b=2")));
		assertEquals(200, response.getStatusLine().getStatusCode(), "Should be successful");

		// Ensure added the values
		String entity = EntityUtils.toString(response.getEntity());
		assertTrue(entity.contains("= 3"), "Should have added the values: " + entity);
	}

JUnit 4 example:

	@Rule
	public final OfficeFloorRule officeFloor = new OfficeFloorRule(this);

	@Rule
	public final HttpClientRule client = new HttpClientRule();

	@Test
	public void callingSystemTest() throws Exception {

		// Send request to add
		HttpResponse response = this.client.execute(new HttpPost(this.client.url("/template+add?a=1&b=2")));
		assertEquals("Should be successful", 200, response.getStatusLine().getStatusCode());

		// Ensure added the values
		String entity = EntityUtils.toString(response.getEntity());
		assertTrue("Should have added the values: " + entity, entity.contains("= 3"));
	}

Injecting dependencies into Tests

Dependencies managed by OfficeFloor can also be injected into tests.

	@Test
	public void injectDependency(Calculator calculator) {
		int result = calculator.plus(1, 2);
		assertEquals(3, result, "Should calculate correct result");
	}

JUnit 4 example:

	private @Dependency Calculator calculator;

	@Test
	public void injectDependency() {
		int result = calculator.plus(1, 2);
		assertEquals("Should calculate correct result", 3, result);
	}

Integration Testing

OfficeFloor provides a Maven plug-in to enable integration testing. The following is the pom.xml plug-ins configuration of running integration tests.

			<!-- Open/Close OfficeFloor for Integration tests -->
			<plugin>
				<groupId>net.officefloor.maven</groupId>
				<artifactId>officefloor-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>open</id>
						<goals>
							<goal>open</goal>
						</goals>
					</execution>
					<execution>
						<id>close</id>
						<goals>
							<goal>close</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<!-- Run Integration tests -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-failsafe-plugin</artifactId>
				<executions>
					<execution>
						<goals>
							<goal>integration-test</goal>
							<goal>verify</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

The integration test is then as follows.

	@RegisterExtension
	public HttpClientExtension client = new HttpClientExtension();

	@Test
	public void integrationTest() throws Exception {

		// Send request to add
		HttpPost request = new HttpPost("http://localhost:7878/template+add?a=1&b=2");
		HttpResponse response = this.client.execute(request);

		// Ensure added the values
		String entity = EntityUtils.toString(response.getEntity());
		assertTrue(entity.contains("= 3"), "Should have added the values: " + entity);
	}

JUnit 4 example:

	@Rule
	public final HttpClientRule client = new HttpClientRule();

	@Test
	public void integrationTest() throws Exception {

		// Send request to add
		HttpPost request = new HttpPost("http://localhost:7878/template+add?a=1&b=2");
		HttpResponse response = this.client.execute(request);

		// Ensure added the values
		String entity = EntityUtils.toString(response.getEntity());
		assertTrue("Should have added the values: " + entity, entity.contains("= 3"));
	}

While this is a simple request test, it also enables using more complex integration test tools (e.g. SeleniumHQ).

Next

The next tutorial looks at configuring OfficeFloor applications.