четверг, 26 сентября 2013 г.

Integration and unit testing with JUnit and Spring Framework

     Testing is the important part of software development. But very often it turns to some kind of challenge. In this article we will use Spring Framework because it provide excellent support for integration and unit testing. 
     Unit testing is used to test a some unit or module in the application in isolation, but integration testing of the application also very important. They help to see different behavior when integrated with other modules in the application. 
     Continuing the previous article, here I’ll show a way to test a service layer with Spring, JUnit, HSQLDB and Maven. First of all, let’s remember the necessary configuration files. Here they are: spring-beans-test.xml, servlet-context-test.xml, persistence-test.xml, all these files are in the src/test/resources package. The description for each file can be found in my previous post. 
     Now we’re ready to write a unit test that will check all the methods of the UserService service.
     Well, a few lines of code speaks more than a thousand words from me...
/**
 * Unit test for the client service layer.
 * 
 * @author Dmitry Nikolaenko
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { 
        "/spring-beans-test.xml", 
        "/servlet-context-test.xml" })
public class UserServiceTest {
    @Autowired
    private UserService userService;
    
    @Test
    public void createTest() {
        User user = userService.create(createTestUser());
        
        Assert.assertNotNull(user);
        Assert.assertNotNull(user.getId());
        Assert.assertEquals("Tom", user.getName());
    }
    
    @Test
    public void deleteTest() {
        User user = userService.create(createTestUser());
        userService.delete(user.getId());
        User deletedUser = userService.find(user.getId());
        
        Assert.assertNull(deletedUser);
    }
    
    @Test
    public void updateTest() {
        User user = userService.create(createTestUser());
        user.setName("Bob");
        userService.update(user);
        User foundUser = userService.find(user.getId());
        
        Assert.assertNotNull(foundUser);
        Assert.assertEquals("Bob", foundUser.getName());
    }
    
    @Test
    public void findTest() {
        User user = userService.create(createTestUser());
        User foundUser = userService.find(user.getId());
        
        Assert.assertNotNull(foundUser);
        Assert.assertNotNull(foundUser.getId());
        Assert.assertEquals("Tom", foundUser.getName());
    }
    
    @Test
    public void getAllTest() {
        userService.create(createTestUser());
        List<User> users = userService.getAll();
        
        Assert.assertNotNull(users);
        Assert.assertFalse(users.isEmpty());
    }
    
    @Test
    public void countTest() {
        userService.create(createTestUser());
        long before = userService.count();
        userService.create(createTestUser());
        long after = userService.count();
        
        Assert.assertEquals(before, after - 1);
    }
    
    /**
     * Create a test user.
     */
    private User createTestUser() {
        User user = new User();
        user.setAge(30);
        user.setName("Tom");
        
        return user;
    }
}
     UserServiceTest annotated as @RunWith(SpringJUnit4ClassRunner.class). Class provides functionality of the Spring TestContext Framework to standard JUnit. It means that Spring JUnit runner allows you to set up Spring ApplicationContext for tests and use dependency injection. 
     @ContextConfiguration(locations = { "/spring-beans-test.xml", "/servlet-context-test.xml" }) tells the path where is located application context to load for test
     @Autowired allow autowired by Spring's dependency injection facilities.
     The source code of our integration test looks as follows.
/**
 * Integration test.
 * 
 * @author Dmitry Nikolaenko
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { 
        "/spring-beans-test.xml", 
        "/servlet-context-test.xml" })
public class UserRestServiceTest {
    private static final String REST_APP_URL = "http://localhost:8080/RESTfulWebApp/rest/users";
    private RestTemplate restTemplate = new RestTemplate();
            
    @Test
    public void addUserTest() {
        // create a new resource by POSTing the given object to the URI template, 
        // and returns the representation found in the response. 
        User createdUser = restTemplate.postForObject(REST_APP_URL, createUser(), User.class);
        
        Assert.assertNotNull(createdUser);
        Assert.assertEquals("Tom", createdUser.getName());
        Assert.assertNotNull(createdUser.getId());
    }
    
    @Test
    public void findUserTest() {
        User createdUser = restTemplate.postForObject(REST_APP_URL, createUser(), User.class);
        
        // retrieve a representation by doing a GET on the specified URL, 
        // the response is converted and returned. 
        User userFound = restTemplate.getForObject(createRestAppUrl(createdUser), User.class);
        Assert.assertNotNull(userFound);
        Assert.assertEquals("Tom", userFound.getName());
        Assert.assertNotNull(userFound.getId());
    }
    
    @Test
    public void updateUserTest() {
        User createdUser = restTemplate.postForObject(REST_APP_URL, createUser(), User.class);
        
        createdUser.setName("Bob");
        // update a resource by PUTing the given user to the URI
        restTemplate.put(createRestAppUrl(createdUser), createdUser);
        User userFound = restTemplate.getForObject(createRestAppUrl(createdUser), User.class);
        
        Assert.assertNotNull(userFound);
        Assert.assertEquals("Bob", userFound.getName());
    }
    
    @Test
    public void loadUsersTest() {
        restTemplate.postForObject(REST_APP_URL, createUser(), User.class);
        Users users = (Users) restTemplate.getForObject(REST_APP_URL, Users.class);
        
        Assert.assertNotNull(users);
        Assert.assertNotNull(users.getUsers());
        Assert.assertFalse(users.getUsers().isEmpty());
    }
    
    @Test
    public void deleteUserTest() {
        // just create new user
        User createdUser = restTemplate.postForObject(REST_APP_URL, createUser(), User.class);
        
        // testing...
        Assert.assertNotNull(createdUser);
        Assert.assertEquals("Tom", createdUser.getName());
        Assert.assertNotNull(createdUser.getId());
        
        // try to find it and then testing...
        User userFound = restTemplate.getForObject(createRestAppUrl(createdUser), User.class);
        Assert.assertNotNull(userFound);
        Assert.assertEquals("Tom", userFound.getName());
        Assert.assertNotNull(userFound.getId());
        
        // delele it
        restTemplate.delete(createRestAppUrl(userFound));
        
        // and finally try to find again, but we lost him forever
        User deletedUser = restTemplate.getForObject(createRestAppUrl(createdUser), User.class);
        Assert.assertNull(deletedUser);
    }
    
    /**
     * Create a test user.
     */
    private User createUser() {
        User user = new User();
        user.setAge(30);
        user.setName("Tom");
        
        return user;
    }
    
    /**
     * Construct REST URL for testing.
     * 
     * @param user for testing
     */
    private String createRestAppUrl(User user) {
        return REST_APP_URL.concat("/").concat(user.getId().toString());
    }
}
     Now you can test functionality with Curl.
http://localhost:8080/RESTfulWebApp/rest/users - get all users (GET) http://localhost:8080/RESTfulWebApp/rest/users - create user (POST) http://localhost:8080/RESTfulWebApp/rest/users/5 - find user by id = 5 (GET) http://localhost:8080/RESTfulWebApp/rest/users/5 - update user with id = 5 (PUT) http://localhost:8080/RESTfulWebApp/rest/users/5 - delete user with id = 5 (DELETE)
     Source code of the project available on Github.

RESTful application with Spring, Hibernate and JPA

     This is a first part of the article where we’ll build a RESTful application with Spring, Hibernate and JPA. For this application we’ll also use Maven for build, HSQLDB(in memory mode) as database to persist the data, Jetty as a server and JUnit as a standalone testing tool. In the second part, it will be another article we’ll see how to test a service layer through unit and integration tests. 
     The goal of the article is to create a RESTful user manager application which will allow create, delete, update, find, getAll or just get a count of users etc.
The Data Access Layer. Generic DAO Pattern
     Very often developers forget about beauty of code, about OOP and using code duplication and copy-and-paste wherever it possible. It may cause a daily nightmares and logical contradictions. DRY-principle(Don’t Repeat Yourself) reduces duplication and very helpful for this situation but it also leads to high coupling and reduced readability. But here we’ll look at slightly different pattern that will help us to save our time and nerves. DAO pattern provides an architectural foundation, type safety and avoid code duplication. Here you find an official information about DAO by Oracle
     Let’s see to the Generic Dao structure of the project.
GenericDao interface can be used for a single specified type domain object. A single instance implementing this interface can be used only for the type of domain object specified in the type parameters.
public interface GenericDao<T extends Serializable> {
    /**
     * Returns the total number of results
     */
    public long count();
    
    /**
     * Create and save new object in DB.
     */
    public T create(T t);
    
    /**
     * Remove the entity with the specified type and id from the datastore.
     */
    public void delete(Object id);
    
    /**
     * Get the entity with the specified type and id from the datastore.
     * 
     * @param id of the entity.
     * @return If none is found, return null.
     */
    public T find(Object id);
    
    /**
     * Get a list of all the objects of the specified type.
     */
    public List<T> getAll();
    
    /**
     * Update object in DB.
     */
    public T update(T t);
}
     GenericDaoImpl abstract class is an implementation of generic DAO with Hibernate. This class offers CRUD method for a generic type T. It should be used only through concrete DAO implementations. Here you can see a Spring @PersistenceContext annotation to inject the entity manager associated with a specific persistence unit. Also an interesting field - Class<T> type, it’s a parametrized type of a class(entity/model) and we use it in EntityManager’s method via reflection.
/**
 * Implementation of Generic DAO. 
 * 
 * @author Dmitry Nikolaenko
 *
 * @param <T> The type of the domain object for which this instance is to be used.
 */
public abstract class GenericDaoImpl<T extends Serializable> implements GenericDao<T> {
    private static final Logger logger = Logger.getLogger(GenericDaoImpl.class);
    
    // parametrized type of a concrete class
    private Class<T> type;
    
    /**
     * Represents a JPA connection to the object database, we can uses 
     * it for CRUD operations (for interacting with the persistence context)
     */
    @PersistenceContext
    protected EntityManager manager;
    
    @SuppressWarnings("unchecked")
    public GenericDaoImpl() {
        Type t = getClass().getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType) t;
        type = (Class<T>) pt.getActualTypeArguments()[0];
    }
    
    @Override
    public long count() {
        String entity = type.getSimpleName();
        final StringBuilder queryString = 
                new StringBuilder("select count(ent) from ".concat(entity).concat(" ent"));
        // create an instance of Query for executing a Java Persistence query language statement
        final Query query = manager.createQuery(queryString.toString());
        // execute a SELECT query that returns a single untyped result
        return (Long) query.getSingleResult();
    }
    
    @Override
    public T find(final Object id) {
        return manager.find(type, id);
    }
    
    @Override
    public T create(T t) {
        manager.persist(t);
        return t;
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public List<T> getAll() {
        Query query = manager.createQuery("from ".concat(type.getName()));
        return query.getResultList();
    }
    
    @Override
    public T update(T t) {
        return manager.merge(t);
    }
    
    @Override
    public void delete(Object id) {
        manager.remove(manager.getReference(type, id));
    }
}
     Before we create the next DAO layer we should bind it with some entity. User class represents a JPA entity which is used by Hibernate and it annotated with JAXB annotations so we can use it via REST. Class Users is a wrapper for the users class and it also contain JAXB annotations.
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
@Entity
@Table(name = "user")
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer id;
    private String name;
    private Integer age;
    
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
}
     Using Hibernate with Spring, standard JPA annotations work very well.
@Entity - specifies that the class is an entity, we tell Hibernate that this class represent an object that we can persist.
@Table(name = "user") - specifies the primary table for the annotated entity.
@GeneratedValue(strategy = GenerationType.SEQUENCE) - provides for the specification of generation strategies for the values of primary keys. GenerationType.SEQUENCE - Indicates that the persistence provider must assign primary keys for the entity using a database sequence.
     Class Users is a wrapper for the users class and it also contain JAXB annotations.
@XmlRootElement
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Users {
    private List<User> users;

    @XmlElement(name = "user")
    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
}
     Now we’re ready to use our abstraction DAO layer in concrete DAO implementation. Time to create an entity interface that extend GenericDao and it’s implementation. UserDao without additional methods but we can add them if needed.
/**
 * Interface for specific User entity because we should tell which entity is acceptable. 
 * 
 * @author Dmitry Nikolaenko
 *
 */
public interface UserDao extends GenericDao<User> {
}
     UserDaoImpl extends generic DAO implementation and implement UserDao interface. @Repository annotation indicates that an annotated class is a "Repository", originally defined by Domain-Driven Design as "a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects". Also we can use @Component annotation instead.
/**
 * Implementation of Generic DAO.
 * 
 * @author Dmitry Nikolaenko
 */
@Repository
public class UserDaoImpl extends GenericDaoImpl<User> implements UserDao {
}
The Service Layer
/**
 * Service for User entity.
 * 
 * @author Dmitry Nikolaenko
 *
 */
public interface UserService {
    public User create(User user);
    public void delete(Integer id);
    public User update(User user);
    public User find(Integer id);
    public List<User> getAll();
    public Long count();
}
     All of the method are transactional, thanks to the @Transactional annotation. @Autowired marks a method as to be autowired by Spring's dependency injection facilities and we inject a user dao implementation.
/**
 * Implementation of the UsersService.
 * 
 * @author Dmitry Nikolaenko
 *
 */
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Override
    @Transactional(readOnly = false)
    public User create(User user) {
        return userDao.create(user);
    }

    @Override
    @Transactional(readOnly = false)
    public void delete(Integer id) {
        userDao.delete(id);
    }

    @Override
    @Transactional(readOnly = false)
    public User update(User user) {
        return userDao.update(user);
    }

    @Override
    @Transactional(readOnly = false)
    public User find(Integer id) {
        return userDao.find(id);
    }

    @Override
    @Transactional(readOnly = true)
    public List<User> getAll() {
        return userDao.getAll();
    }

    @Override
    @Transactional(readOnly = true)
    public Long count() {
        return userDao.count();
    }
}
      Well, build a RESTful using Spring Framework.
     Configure servlet dispatcher to handle our request in web.xml. And hand this Servlet to handle incoming requests starting with "/rest/*". We use the ContextConfigLocation init parameter to change the location for the main config XML file for the Spring Application Context that is loaded by the DispatcherServlet.
<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
    <display-name>Restful Web Application</display-name>
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring-beans.xml</param-value>
    </context-param>

    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath*:log4j.properties</param-value>
    </context-param>
    
    <!-- Processes application requests -->
    <servlet>
        <servlet-name>servlet-context</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
         <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/servlet-context.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>servlet-context</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
</web-app>
     Configure the datasource and persistence unit via Spring and using Hibernate as the JPA provider. The spring-beans.xml file contains different spring mappings such as transaction manager, entity manager factory bean, data source etc. 
 - dataSource bean - java datasource used to connect to contact manager database, we should provide driver class name, username, password etc
 - entityManagerFactory bean - the LocalContainerEntityManagerFactoryBean gives full control over EntityManagerFactory configuration. LocalContainerEntityManagerFactoryBean will create a PersistenceUnitInfo based on the persistence.xml file. This is really great JPA option, allowing for flexible local configuration within the application. It supports links to an existing JDBC DataSource, supports both local and global transactions.
 - transactionManager bean - Transaction manager for EntityManagerFactory
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- Configure the JDBC datasource -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
        <property name="url" value="jdbc:hsqldb:mem:testdb" />
        <property name="username" value="sa" />
        <property name="password" value="" />
    </bean>
    
    <!-- Configure the entity manager -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceXmlLocation" value="classpath:persistence.xml"/>
        <property name="persistenceUnitName" value="spring-persistenceUnit" />
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- Transaction manager for EntityManagerFactory -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    
    <persistence-unit name="spring-persistenceUnit">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>com.dmitrynikol.model.User</class>
        <properties>
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
            <property name="hibernate.hbm2ddl.auto" value="create" />
            <property name="hibernate.show_sql" value="true" />
        </properties>
    </persistence-unit>
</persistence>
     Create a servlet context file servlet-context.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:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/mvc 
    http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <!-- Enabling Spring beans auto-discovery,  
         scans the classpath of this application for annotation to deploy the bean.
         It help us to find class annotated with @Controller, 
         @Service, @Configuration etc annotation. -->
    <context:component-scan base-package="com.dmitrynikol" />
    
    <!-- Enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <!-- Enabling Spring MVC configuration through annotations. 
         Configures the @Controller programming model -->
    <mvc:annotation-driven />
</beans>
     UserRestService represent a class that will be manipulated by different HTTP methods. The class has been annotated with the @Controller annotation, it means that this is Spring MVC controller able to handling web requests. @RequestMapping annotation mapping web requests onto our REST class that handles path "/users". All methods has been annotated also with @RequestMapping annotation for handling different requests. 
     For example, @RequestMapping(method = RequestMethod.POST) will be invoked on the post request. We annotate returning Java object with @ResponseBody annotation which indicates that a method return value should be bound to the web response body.
/**
 * Represent a class that will be manipulated by different HTTP methods.
 * 
 * @author Dmitry Nikolaenko
 *
 */
@Controller
@RequestMapping("/users")
public class UserRestService {
    @Autowired
    private UserService userService;
    
    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public Users loadUsers() {
        Users users = new Users();
        users.setUsers(userService.getAll());
        return users;
    }
    
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    @ResponseBody
    public User updateUser(@PathVariable(value = "id") Integer id, @RequestBody User user) {
        return userService.update(user);
    }
    
    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public User addUser(@RequestBody User user) {
        return userService.create(user);
    }
    
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    @ResponseBody
    public void deleteUser(@PathVariable(value = "id") Integer id) {
        userService.delete(id);
    }
    
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public User findUser(@PathVariable(value = "id") Integer id) {
        return userService.find(id);
    }
}
     Here is a link to the Maven POM file to build the above project.
     At this point, we’ve got a final RESTful application, the next thing to do is write a unit and integration test for service layer. But I'll describe this in the next article.
     The code for this and the next article is available on Github.