Spring Book – Chapter 7 – Testing

Mocks or Stubs?

Now the million dollar question, in your application, whether to use mocks or stubs? Which is the best approach and which framework to be used?

This is a very difficult question to answer with authority and confidence. I would say that, understand exactly what a stub and mock is and then use these judiciously in your application. It could be that you use both stubs and mocks interchangeably in your application. I don’t see anything wrong in this and would suggest that it’s your choice and it should only be picked considering various factors in the application in which you would like to use.

General recommendation according to me which can be used is as given below:

  • Mock anything that involves any kind of call or access to things outside of the application domain. Example being mocking data access layer when testing your services
  • Be careful about mocking or stubbing any interface that is outside your own codebase. In this case, create your own interface to wrap the interaction with the external API classes and then mock these interfaces.
  • Don’t mock fine grained interfaces. Favor mocks for non-trivial interfaces.
  • Use stubs in case of simple interface having repeated functionality
  • Be cautious while mocking an abstract class or a concrete class.  My advice is to only mock interfaces to avoid unwanted side effects.
  • Mock only the dependencies of the class being tested, not the dependencies of the dependencies.

Ideally it’s not good to have 1-2 mock objects involved in a single unit test. It is not a hard and fast rule but having more than 2-3 mocks in a single unit test is a question raised against your application design.

Unit tests and mock objects can be used as one of the means to gather feedback about your code and design.  If you’re having difficulty using a mock object in a unit test, or you’re incurring more setup overhead in your tests, it’s often a sign that you need to reassess your class design.

Integration Testing with Spring

Integration test is used to ascertain interaction of various units in your application. In this testing you test your application classes in the context of their surrounding infrastructure. Unit tests don’t go to the actual data sources; they are fast and simple in structure. Integration tests hit the actual data sources and test multiple modules together in an application.

The official documentation suggests that you use org.springframework.test.context.junit38.AbstractJUnit38SpringContextTests. If you are using JUnit 4 you would rather use org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests.These are abstract base test classes which integrates the Spring TestContext framework with explicit ApplicationContext testing support in a JUnit environment. The central support class provided by Spring is org.springframework.test.context.junit4.SpringJUnit4ClassRunner. A typical integration test written in Spring is shown in Listing 7-9.

Listing 7-9. Sample integration test class in Spring

[java]@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = { "file:src/test/resources/applicationContext-test.xml" })

@TransactionConfiguration(transactionManager = "myTransactionManager", defaultRollback = true)

@Transactional

public class CustomerServiceImplTests {

// …

}[/java]

The various annotation used in Listing 7-9 is detailed below for clarity.

  • @RunWith(SpringJUnitClassRunner.class) – Setting this annotation’s value to SpringJUnit4ClassRunner.class tells JUnit to use Spring’s TestContext framework (Next section covers Spring TestContext framework in detail) test runner, rather than JUnit’s built in test runner.
  • @ContextConfiguration – It’s responsible for telling Spring where to find your application context configuration files.  It could be given a single value or a String[] of values.
  • @TransactionConfiguration –transaction requirement configuration happens here. The transaction manager is configured and also various properties with respect to transaction is done.
  • @Transactional – Says that all the methods in this class should participate in a transaction. This is important if you want to rollback a transaction.

SpringJUnit4ClassRunner is a custom runner provided by Spring TestContext framework which offers full integration with jUnit4.5+. The following list constitutes annotations currently supported directly by SpringJUnit4ClassRunner class:

  • org.junit.Test – The Test annotation tells JUnit that the public void method to which it is attached can be run as a test case.  Any exceptions thrown by the test will be reported by JUnit as a failure. If no exceptions are thrown, the test is assumed to have succeeded. Supports two optional parameters. The first one namely expected, a Throwable, causes a test method to succeed if an exception of the specified class is thrown by the method. The second one timeout, causes a test to fail if it takes longer than a specified amount of clock time (measured in milliseconds).
  • org.springframework.test.annotation.Timed – Test-specific annotation to indicate that a test method has to finish execution in a specified time period (milliseconds).If the text execution takes longer than the specified time period, then the test is to be considered failed.
  • org.springframework.test.annotation.Repeat – Test annotation to indicate that a test method should be invoked repeatedly.
  • org.junit.Ignore – Methods annotated with Test that are also annotated with @Ignore will not be executed as tests. Also, you can annotate a class containing test methods with @Ignore and none of the containing tests will be executed.
  • org.springframework.test.annotation.ProfileValueSourceConfiguration – used to specify what type of ProfileValueSource to use when retrieving profile values configured via the @IfProfileValue annotation.
  • org.springframework.test.annotation.IfProfileValue – Test annotation to indicate that a test is enabled for a specific testing profile or environment. If the configured ProfileValueSource returns a matching value for the provided name, the test will be enabled. Can be applied at the class level, the method level, or both.
  • org.springframework.test.annotation.DirtiesContext – indicates that the ApplicationContext associated with a test is dirty and should be closed. When declared at method level, the context is closed after the current test.  When declared in the class level with mode set to AFTER_EACH_TEST_METHOD, context is closed after each test method. When declared in class level with mode set to AFTER_CLASS, the context is closed only after the current test class.

Spring TestContext Framework

The Spring TestContext framework provides several abstract support classes that simplify the writing of integration tests. These base test classes provide well-defined hooks into the testing framework as well as convenient instance variables and methods which can be used easily in your application.

In addition to generic testing infrastructure, the TestContext framework provides specific support for JUnit and TestNG frameworks in the form of abstract classes. The org.springframework.test.context.testng package provides support classes for TestNG and org.springframework.test.context.junit4 package provides support classes for JUnit 4.5+ based test cases. The core of the framework consists of classes namely TestContext and TextContextManager and interfaces namely TestExecutionListener, ContextLoader, and SmartContextLoader.

  • TestContext – its role is to encapsulate the context in which the test is executed. It provides caching and context management for the test instance.
  • TestContextManager – main entry point to the Spring TestContext framework. It maintains exactly one TestContext instance and sends signals to all registered TestExecutionListeners at defined intervals.
  • TestExecutionListener – defines a listener API for reacting to the signals send by TestContextManager.
  • ContextLoader – aids in loading the ApplicationContext for an integration test managed by Spring TestContext framework.
  • SmartContextLoader – extension of ClassLoader interface.it can choose to process resource locations (XML configurations) or configuration classes (Java Configuration classes).

In the TestContext framework, transactions are managed by the TransactionalTestExecutionListener. This listener is configured by default, even if you do not explicitly declare @TestExecutionListeners on your test class. To enable support for transactions, however, you must provide a PlatformTransactionManager bean in the application context loaded by @ContextConfiguration semantics. In addition, you must declare @Transactional either at the class or method level for your tests. TransactionalTestExecutionListener supports the @BeforeTransaction and @AfterTransaction annotations which can be used to execute certain code before or after a transactional test method but outside the transactional context. Simply annotate any public void method in your test class with one of these annotations and the listener will take care of its execution at right time. Listing 7-10 shows usage of @BeforeTransaction and @AfterTransaction annotations used in a test class.


Listing 7-10. Usage of transaction annotation in an integration test class

[java]@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = { "file:src/test/resources/applicationContext-test.xml" })

@TransactionConfiguration(transactionManager = "myTransactionManager", defaultRollback = true)

@Transactional

public class CustomerServiceImplTests {

@BeforeTransaction

public void checkPreHooks() {

//logic to verify initial state before transaction starts

}

@Before

public void settingUpDataWithinTransaction() {

// setting up within the transaction

}

@Test

public void actualTestWithinTransaction() {

// actual trasaction

}

@After

public void releaseWithinTransaction() {

// release logic within transaction

}

@AfterTransaction

public void checkPostHooks() {

// logic which verifies state after transaction

}

}[/java]

TestContext Support Classes

As explained in earlier sections Spring TestContext framework provides abstract support classes for writing integration testing using frameworks like JUnit and TestNG. We will see support classes provided by Spring for writing integration tests using JUnit and TestNG framework to some detail below.

JUnit Support Classes

The package org.springframework.test.context.junit4 provides all the necessary classes for supporting JUnit based integration tests for your Spring application. Important classes are:

  • AbstractJUnit4SpringContextTests – Abstract base test class which integrates the Spring TestContext framework with explicit ApplicationContext testing support in a JUnit 4.5+ environment. While extending this class, you will have access to protected instance variable applicationContext which can be used to lookup other beans or to test the state of the context as a whole.
  • AbstractTransactionalJUnit4SpringContextTests – Abstract transactional extension of AbstractJUnit4SpringContextTests which adds convenience functionality for JDBC access. Expects a DataSource bean and a PlatformTransactionManager bean to be defined in the Spring application context. In addition to access to protected variable applicationContext, this class exposes a SimpleJdbcTemplate and provides an easy way to execute SQL scripts within a transaction.

TestNG Support Classes

org.springframework.text.context.testng is the package which contains classes for supporting TestNG framework based integration tests. The classes are very much similar to what we have seen for JUnit support. Important classes are:

  • AbstractTestNGSpringContextTests – Abstract base test class which integrates the Spring TestContext framework with explicit ApplicationContext testing support in a TestNG environment. Similar to JUnit support class, while extending this class, you will have access to protected instance variable applicationContext which can be used to lookup other beans or to test the state of the context as a whole.
  • AbstractTransactionalTestNGSpringContextTests – Abstract transactional extension of AbstractTestNGSpringContextTests which adds convenience functionality for JDBC access. Expects a DataSource bean and a PlatformTransactionManager bean to be defined in the Spring application context. In addition to access to protected variable applicationContext, this class exposes a SimpleJdbcTemplate and provides an easy way to execute SQL scripts within a transaction.

Advantages of Integration Testing with Spring

Advantages of doing integration testing using the Spring framework can be summarized as below:

  • Deploying of your application to an external container is not required
  • Have the provision of running your integration tests within your favorite IDE itself
  • Support for profiles for grouping various configurations is really advantageous. It also allows reusing your configurations between test and real production environment.

Summary

Testing is an integral part of any software development.  Unit tests help us to test a class in isolation wherein care is taken to avoid dependencies from external is minimized. Integration test on the other hand tests the interaction of multiple units in an application to see that as a single unit these small units work together to realize a use case.

After reading through this chapter you should have now got a clear picture of the importance of various testing methodologies in your application development. I have covered these methodologies in detail, along with the support provided by Spring to do these effectively. For each methodology I have tried to explain to some detail as how we can use the various open source frameworks available, and integrate easily into your Spring application. In unit testing I have covered stubbing and mocking in detail along with the frameworks that are popular at this point in time in the industry.

Page Visitors: 5829

The following two tabs change content below.
Tomcy John

Tomcy John

Blogger & Author at javacodebook
He is an Enterprise Java Specialist holding a degree in Engineering (B-Tech) with over 10 years of experience in several industries. He's currently working as Principal Architect at Emirates Group IT since 2005. Prior to this he has worked with Oracle Corporation and Ernst & Young. His main specialization is on various web technologies and acts as chief mentor and Architect to facilitate incorporating Spring as Corporate Standard in the organization.
Tomcy John

Latest posts by Tomcy John (see all)

6 thoughts on “Spring Book – Chapter 7 – Testing

  1. I wanted to put you the little note to finally thank you over again with your wonderful knowledge you’ve documented on this page. This is really shockingly generous of people like you to deliver publicly all most people would’ve made available as an e book to earn some cash for their own end, primarily considering the fact that you might have tried it if you wanted. Those tips likewise acted like the fantastic way to be sure that someone else have similar zeal just as my own to realize many more in regard to this issue. I’m certain there are several more pleasurable sessions up front for people who see your blog.

  2. Hello There. I found your blog using msn. This is an extremely well written article. I will be sure to bookmark it and come back to read more of your useful info. Thanks for the post. I will certainly comeback.

Leave a Reply

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