Functional testing Java-EE applications with TestEE.fi – Part 2: Mocking with Mockito and EasyMock

Functional testing Java-EE applications often requires validating the behavior of your business logic in interaction with one or more surrounding systems. Usually it’s not desirable to actually interact with these systems from your automated functional test cases as this can introduce non-deterministic behavior and jeopardizes repeatability – two very important aspects of solid testing.

TestEE.fi helps you writing relevant and robust functional test cases for Java-EE applications by offering out-of-the-box support for popular mocking tools like Mockito and EasyMock.

In Part 1 we took a look at the advantages TestEE.fi offers for functional testing Java-EE applications and concluded with a bare-bones example of how to write your first TestEE.fi based JUnit 4 test. The sample code in Part 1 already gave a small hint on how mocking classes in your tests works and in this second installment we take a closer look at how in TestEE.fi mocking with both Mockito and EasyMock is a first class citizen.

Project setup

If you add the “testeefi-junit4-all” dependency to your project, you have the Mockito integration already in your classpath. For EasyMock you have to add another entry to your project’s dependencies:

<dependencies>
	<dependency>
		<groupId>fi.testee</groupId>
		<artifactId>testeefi-junit4-all</artifactId>
		<version>0.6.1</version>
		<scope>test</scope>
	</dependency>
	
	<!-- Add EasyMock support -->
	<dependency>
		<groupId>fi.testee</groupId>
		<artifactId>testeefi-easymock</artifactId>
		<version>0.6.1</version>
		<scope>test</scope>
	</dependency>
	
	<!-- TestEE.fi uses slf4j, so add logback as logging implementation -->
	<dependency>
		<groupId>ch.qos.logback</groupId>
		<artifactId>logback-classic</artifactId>
		<version>1.1.7</version>
		<scope>test</scope>
	</dependency>
</dependencies>
TestEE.fi EasyMock integration with Maven

For Gradle the snippet looks like this:

dependencies {
	testCompile 'fi.testee:testeefi-junit4-all:0.6.1'
	testCompile 'fi.testee:testeefi-easymock:0.6.1'
	testCompile 'ch.qos.logback:logback-classic:1.1.7'
}
TestEE.fi EasyMock integration with Gradle

Example program

In order to understand how mocking is used in TestEE.fi let me introduce some example classes first and then show both the usage of Mockito and EasyMock to replace certain EJBs or CDI managed beans with mocks at test runtime.

Let’s assume we want to write a program that notifies us when a website is not available. I will distribute this logic into four classes:

  • HttpCheckingAdapter: performs a HTTP request to check if some URL is available.
  • EmailDispatchAdapter: sends E-Mails.
  • AlertingService: orchestrates the other two beans in order to fulfill the use case.
  • AlertingFacade: being a professional developer I hide my business logic behind a facade that performs cross-cutting concerns like transactions or logging.
public class HttpCheckingAdapter {
	public boolean checkUrl(String url) {
		// HTTP request here, returns true if URL is available, false otherwise
	}
}
class HttpCheckingAdapter
public class EmailDispatchAdapter {
	public void sendEmail(String address, String subject, String body) {
		// Dispatch the E-Mail
	}
}
class EmailDispatchAdapter
public class AlertingService {
	@Inject
	private HttpCheckingAdapter httpCheckingAdapter;
	@Inject
	private EmailDispatchAdapter emailDispatchAdapter;
	
	public void alertIfUnavailable(String url) {
		if(!httpCheckingAdapter.checkUrl(url)) {
			emailDispatchAdapter.sendEmail(
				"alex@it-stockinger.de", 
				url + " is down",
				"The URL " + url + " could not be reached"
			);
		}
	}
}
class AlertingService
public class AlertingFacade {
	private static final Logger LOG = LoggerFactory.getLogger(AlertingFacade.class);
	
	@Inject
	private AlertingService alertingService;
	
	public void alertIfUnavailable(String url) {
		LOG.info("Checking URL: {}", url);
		alertingService.alertIfUnavailable(url);
	}
}
class AlertingFacade

Testing the application with mocks

Now that we have the sample code established we continue to the actual test class. I will write the test using the facade class as “test subject” (as you should when you’re testing your business use cases) and I will mock away both Adapter classes which would normally require access to external systems – unsuitable for repeatable independent testing of your application.

@RunWith(TestEEfi.class)
public class AlertingFacadeTest {
	@Mock
	private HttpCheckingAdapter httpCheckingAdapter;
	@Mock
	private EmailDispatchAdapter emailDispatchAdapter;
	@Inject
	private AlertingFacade underTest;
	
	@Test
	public void dispatchesEmailWhenUnreachable() {
		// Test code goes here
	}
	
	@Test
	public void notDispatchesEmailWhenReachable() {
		// Test code goes here
	}
}
Basic test class with mocks

It might surprise you (or not) that the test class (at least until this point) looks the same regardless whether you are using Mockito or EasyMock. Both provide a @Mock annotation and use it in basically the same way. Consequently the only difference for this test class is the import statement for the @Mock annotation as they (unsurprisingly) reside in different packages for the two mocking libraries.

Let’s take a quick look at what’s going to happen here when we run the test:

  1. A new instance of your test class is instantiated for the test method (this happens for each test method and this is standard JUnit behavior)
  2. Mocks are created for the two fields annotated with @Mock and injected into the test class instance
  3. An instance of AlertingFacade is instantiated and injected into your test case
  4. An instance of AlertingService is instantiated and injected into AlertingFacade
  5. The two mocks are injected instead of actual bean instances in AlertingService
  6. The test method is executed

Notice how in step 4 the instantiation and injection of unmocked beans is performed as it would at runtime by the application server. This is due to TestEE.fi wiring your application as it would run in production and only taking a special detour for mocked classes – it supports the full range of CDI dependency injection mechanisms (such as @Produces methods, constructor injection, qualifier annotations etc.) and even advanced EJB style dependency injection patterns like circular references or self-injection.

Now everything is ready for setting up some behavior for our mocks and actually testing our business logic. As the actual implementation of the test method differs between the two mocking libraries I will start with the Mockito incarnation of our test method and will the move on to the EasyMock implementation.

Testing in TestEE.fi with Mockito

@Test
public void dispatchesEmailWhenUnreachable() {
	// Given
	when(httpCheckingAdapter.checkUrl(any())).thenReturn(false);
	
	// When
	underTest.alertIfUnavailable("http://www.example.com");
	
	// Then
	verify(emailDispatchAdapter).sendEmail(
		"alex@it-stockinger.de",
		"http://www.example.com is down",
		"The URL http://www.example.com could not be reached"
	);
}

@Test
public void notDispatchesEmailWhenReachable() {
	// Given
	when(httpCheckingAdapter.checkUrl(any())).thenReturn(true);
	
	// When
	underTest.alertIfUnavailable("http://www.example.com");
	
	// Then
	verify(emailDispatchAdapter, never()).sendEmail(any(), any(), any());
}
Test methods for Mockito

Since this is not a tutorial on how Mockito works in detail I won’t dive too deep into the actual test code implementation. Note however how Mockito aligns nicely to the BDD-style Given-When-Then pattern (which I really like) and allows us to express the behavior we expect from our mocks in a very clean and concise fashion.

Testing in TestEE.fi with EasyMock

@Test
public void dispatchesEmailWhenUnreachable() {
	expect(httpCheckingAdapter.checkUrl("http://www.example.com")).andReturn(false).once();
	emailDispatchAdapter.sendEmail(
		"alex@it-stockinger.de",
		"http://www.example.com is down",
		"The URL http://www.example.com could not be reached"
	);
	expectLastCall().once();
	replay(httpCheckingAdapter, emailDispatchAdapter);

	underTest.alertIfUnavailable("http://www.example.com");

	verify(httpCheckingAdapter, emailDispatchAdapter);
}

@Test
public void notDispatchesEmailWhenReachable() {
	expect(httpCheckingAdapter.checkUrl("http://www.example.com")).andReturn(true);
	replay(httpCheckingAdapter, emailDispatchAdapter);

	underTest.alertIfUnavailable("http://www.example.com");

	verify(httpCheckingAdapter, emailDispatchAdapter);
}
Test methods for EasyMock

As with Mockito, since this is not an in-depth tutorial on EasyMock, we’ll leave it at simply presenting the code – for this simple example use-case it’s rather self-explanatory anyway. Note however how, in contrast to the BDD-style of the previous example, EasyMock relies on a record-replay-verify pattern that feels more like a movie script your code has to follow.

Both styles of mocking have their up- and downsides and it’s good to know that whichever you need or prefer, TestEE.fi makes it easy to use either one of them (or even both of them) in your tests.

Conclusion

In this quick installment you’ve learned how to use both Mockito and EasyMock together with TestEE.fi and you’ve seen first hand how mocking integrates in a very natural fashion with CDI injection. The example we’ve used demonstrated the primary purpose of mocking when you’re functional testing whole use-cases: the ability to replace external systems with customizable and reproducible behavior.

The source code of the sample application on which the examples above are based can be found here.

If you want to know more about advanced testing with TestEE.fi, be sure to check out the other posts of this series to get you up to speed quickly:

Leave a Reply

Your email address will not be published. Required fields are marked *