Spring Testing Support with TestNG
Spring testing support covers very useful and important features for unit and integration testing of spring based applications. The org.springframework.test.context.testng package provides support classes for TestNG based test cases. This article shows how to test Spring Service layer components by using Spring and TestNG integration. Also next article will show how to test Spring Data Access layer components by using same integration.
Used Technologies :
JDK 1.6.0_31
Spring 3.1.1
TestNG 6.4
Maven 3.0.2
STEP 1 : CREATE MAVEN PROJECT
A maven project is created as follows. (It can be created by using Maven or IDE Plug-in).
STEP 2 : LIBRARIES
Spring dependencies are added to Maven’ s pom.xml.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | < properties > < spring.version >3.1.1.RELEASE</ spring.version > </ properties > < dependencies > <!-- Spring 3 dependencies --> < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-core</ artifactId > < version >${spring.version}</ version > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-context</ artifactId > < version >${spring.version}</ version > </ dependency > < dependency > < groupId >org.springframework</ groupId > < artifactId >spring-test</ artifactId > < version >${spring.version}</ version > </ dependency > <!-- TestNG dependency --> < dependency > < groupId >org.testng</ groupId > < artifactId >testng</ artifactId > < version >6.4</ version > </ dependency > <!-- Log4j dependency --> < dependency > < groupId >log4j</ groupId > < artifactId >log4j</ artifactId > < version >1.2.16</ version > </ dependency > </ dependencies > |
STEP 3 : CREATE USER CLASS
A new User Class is created.
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | package com.otv.user; /** * User Bean * * @author onlinetechvision.com * @since 19 May 2012 * @version 1.0.0 * */ public class User { private String id; private String name; private String surname; /** * Gets User Id * * @return String id */ public String getId() { return id; } /** * Sets User Id * * @param String id */ public void setId(String id) { this .id = id; } /** * Gets User Name * * @return String name */ public String getName() { return name; } /** * Sets User Name * * @param String name */ public void setName(String name) { this .name = name; } /** * Gets User Surname * * @return String Surname */ public String getSurname() { return surname; } /** * Sets User Surname * * @param String surname */ public void setSurname(String surname) { this .surname = surname; } @Override public String toString() { StringBuilder strBuilder = new StringBuilder(); strBuilder.append( "Id : " ).append(getId()); strBuilder.append( ", Name : " ).append(getName()); strBuilder.append( ", Surname : " ).append(getSurname()); return strBuilder.toString(); } @Override public int hashCode() { final int prime = 31 ; int result = 1 ; result = prime * result + ((id == null ) ? 0 : id.hashCode()); result = prime * result + ((name == null ) ? 0 : name.hashCode()); result = prime * result + ((surname == null ) ? 0 : surname.hashCode()); return result; } @Override public boolean equals(Object obj) { if ( this == obj) return true ; if (obj == null ) return false ; if (getClass() != obj.getClass()) return false ; User other = (User) obj; if (id == null ) { if (other.id != null ) return false ; } else if (!id.equals(other.id)) return false ; if (name == null ) { if (other.name != null ) return false ; } else if (!name.equals(other.name)) return false ; if (surname == null ) { if (other.surname != null ) return false ; } else if (!surname.equals(other.surname)) return false ; return true ; } } |
STEP 4 : CREATE NonExistentUserException CLASS
NonExistentUserException Class is created.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | package com.otv.common.exceptions; /** * Non Existent User Exception * * @author onlinetechvision.com * @since 19 May 2012 * @version 1.0.0 * */ public class NonExistentUserException extends Exception { private static final long serialVersionUID = 1L; public NonExistentUserException(String message) { super (message); } } |
STEP 5 : CREATE ICacheService INTERFACE
ICacheService Interface representing a cache service interface, is created.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.otv.cache.service; import java.util.concurrent.ConcurrentHashMap; import com.otv.user.User; /** * Cache Service Interface * * @author onlinetechvision.com * @since 19 May 2012 * @version 1.0.0 * */ public interface ICacheService { /** * Gets User Map * * @return ConcurrentHashMap User Map */ ConcurrentHashMap<String, User> getUserMap(); } |
STEP 6 : CREATE CacheService CLASS
CacheService Class is created by implementing ICacheService Interface. It provides access to the remote cache…
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package com.otv.cache.service; import java.util.concurrent.ConcurrentHashMap; import com.otv.user.User; /** * Cache Service Implementation * * @author onlinetechvision.com * @since 19 May 2012 * @version 1.0.0 * */ public class CacheService implements ICacheService { //User Map is injected... private ConcurrentHashMap<String, User> userMap; /** * Gets User Map * * @return ConcurrentHashMap User Map */ public ConcurrentHashMap<String, User> getUserMap() { return userMap; } /** * Sets User Map * * @param ConcurrentHashMap User Map */ public void setUserMap(ConcurrentHashMap<String, User> userMap) { this .userMap = userMap; } } |
STEP 7 : CREATE IUserService INTERFACE
IUserService Interface representing User Service interface is created.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | package com.otv.user.service; import java.util.Collection; import com.otv.common.exceptions.NonExistentUserException; import com.otv.user.User; /** * * User Service Interface * * @author onlinetechvision.com * @since 19 May 2012 * @version 1.0.0 * */ public interface IUserService { /** * Adds User * * @param User user * @return boolean whether delete operation is success or not. */ boolean addUser(User user); /** * Deletes User * * @param User user * @return boolean whether delete operation is success or not. */ boolean deleteUser(User user); /** * Updates User * * @param User user * @throws NonExistentUserException */ void updateUser(User user) throws NonExistentUserException; /** * Gets User * * @param String User Id * @return User */ User getUserById(String id); /** * Gets User Collection * * @return List - User list */ Collection<User> getUsers(); } |
STEP 8 : CREATE UserService CLASS
UserService Class is created by implementing IUserService Interface.
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 | package com.otv.user.service; import java.util.Collection; import com.otv.cache.service.ICacheService; import com.otv.common.exceptions.NonExistentUserException; import com.otv.user.User; /** * * User Service * * @author onlinetechvision.com * @since 19 May 2012 * @version 1.0.0 * */ public class UserService implements IUserService { //CacheService is injected... private ICacheService cacheService; /** * Adds User * * @param User user * @return boolean whether delete operation is success or not. */ public boolean addUser(User user) { getCacheService().getUserMap().put(user.getId(), user); if (getCacheService().getUserMap().get(user.getId()).equals(user)) { return true ; } return false ; } /** * Deletes User * * @param User user * @return boolean whether delete operation is success or not. */ public boolean deleteUser(User user) { User removedUser = getCacheService().getUserMap().remove(user.getId()); if (removedUser != null ) { return true ; } return false ; } /** * Updates User * * @param User user * @throws NonExistentUserException */ public void updateUser(User user) throws NonExistentUserException { if (getCacheService().getUserMap().containsKey(user.getId())) { getCacheService().getUserMap().put(user.getId(), user); } else { throw new NonExistentUserException( "Non Existent User can not update! User : " +user); } } /** * Gets User * * @param String User Id * @return User */ public User getUserById(String id) { return getCacheService().getUserMap().get(id); } /** * Gets User List * * @return Collection - Collection of Users */ public Collection<User> getUsers() { return (Collection<User>) getCacheService().getUserMap().values(); } /** * Gets Cache Service * * @return ICacheService - Cache Service */ public ICacheService getCacheService() { return cacheService; } /** * Sets Cache Service * * @param ICacheService - Cache Service */ public void setCacheService(ICacheService cacheService) { this .cacheService = cacheService; } } |
STEP 9 : CREATE UserServiceTester CLASS
User Service Tester Class is created by extending AbstractTestNGSpringContextTests.
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | package com.otv.user.service.test; import junit.framework.Assert; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import com.otv.common.exceptions.NonExistentUserException; import com.otv.user.User; import com.otv.user.service.IUserService; /** * User Service Tester Class * * @author onlinetechvision.com * @since 19 May 2012 * @version 1.0.0 * */ @ContextConfiguration (locations={ "classpath:applicationContext.xml" }) public class UserServiceTester extends AbstractTestNGSpringContextTests { private static Logger logger = Logger.getLogger(UserServiceTester. class ); @Autowired private IUserService userService; private User firstUser; private User secondUser; private User thirdUser; /** * Creates Test Users * */ private void createUsers() { firstUser = new User(); firstUser.setId( "1" ); firstUser.setName( "Lionel" ); firstUser.setSurname( "Messi" ); secondUser = new User(); secondUser.setId( "2" ); secondUser.setName( "David" ); secondUser.setSurname( "Villa" ); thirdUser = new User(); thirdUser.setId( "3" ); thirdUser.setName( "Andres" ); thirdUser.setSurname( "Iniesta" ); } /** * Asserts that User Properties are not null. * * @param User */ private void assertNotNullUserProperties(User user) { Assert.assertNotNull( "User must not be null!" , user); Assert.assertNotNull( "Id must not be null!" , user.getId()); Assert.assertNotNull( "Name must not be null!" , user.getName()); Assert.assertNotNull( "Surname must not be null!" , user.getSurname()); } /** * The annotated method will be run before any test method belonging to the classes * inside the <test> tag is run. * */ @BeforeTest public void beforeTest() { logger.debug( "BeforeTest method is run..." ); } /** * The annotated method will be run before the first test method in the current class * is invoked. * */ @BeforeClass public void beforeClass() { logger.debug( "BeforeClass method is run..." ); createUsers(); } /** * The annotated method will be run before each test method. * */ @BeforeMethod public void beforeMethod() { logger.debug( "BeforeMethod method is run..." ); } /** * Tests the process of adding user * */ @Test public void addUser() { assertNotNullUserProperties(firstUser); Assert.assertTrue( "User can not be added! User : " + firstUser, getUserService().addUser(firstUser)); } /** * Tests the process of querying user * */ @Test public void getUserById() { User tempUser = getUserService().getUserById(firstUser.getId()); assertNotNullUserProperties(tempUser); Assert.assertEquals( "Id is wrong!" , "1" , tempUser.getId()); Assert.assertEquals( "Name is wrong!" , "Lionel" , tempUser.getName()); Assert.assertEquals( "Surname is wrong!" , "Messi" , tempUser.getSurname()); } /** * Tests the process of deleting user * */ @Test public void deleteUser() { assertNotNullUserProperties(secondUser); Assert.assertTrue( "User can not be added! User : " + secondUser, getUserService().addUser(secondUser)); Assert.assertTrue( "User can not be deleted! User : " + secondUser, getUserService().deleteUser(secondUser)); } /** * Tests the process of updating user * @throws NonExistentUserException * */ @Test (expectedExceptions = NonExistentUserException. class ) public void updateUser() throws NonExistentUserException { getUserService().updateUser(thirdUser); } /** * Test user count * */ @Test public void getUserCount() { Assert.assertEquals( 1 , getUserService().getUsers().size()); } /** * The annotated method will be run after all the test methods in the current class have been run. * */ @AfterClass public void afterClass() { logger.debug( "AfterClass method is run..." ); } /** * The annotated method will be run after all the test methods belonging to the classes inside the <test> tag have run. * */ @AfterTest public void afterTest() { logger.debug( "AfterTest method is run..." ); } /** * The annotated method will be run after each test method. * */ @AfterMethod public void afterMethod() { logger.debug( "AfterMethod method is run..." ); } /** * Gets User Service * * @return IUserService User Service */ public IUserService getUserService() { return userService; } /** * Sets User Service * * @param IUserService User Service */ public void setUserService(IUserService userService) { this .userService = userService; } } |
STEP 10 : CREATE applicationContext.xml
Application Context is created as follows :
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | xsi:schemaLocation="http://www.springframework.org/schema/beans <!-- User Map Declaration --> < bean id = "UserMap" class = "java.util.concurrent.ConcurrentHashMap" /> <!-- Cache Service Declaration --> < bean id = "CacheService" class = "com.otv.cache.service.CacheService" > < property name = "userMap" ref = "UserMap" /> </ bean > <!-- User Service Declaration --> < bean id = "UserService" class = "com.otv.user.service.UserService" > < property name = "cacheService" ref = "CacheService" /> </ bean > </ beans > |
STEP 11 : RUN PROJECT
In this article, TestNG Eclipse Plugin has been used. If you use Eclipse, it can be downloaded via TestNG download page
If UserServiceTester is run, results of the test cases are shown as follows :
STEP 12 : DOWNLOAD
REFERENCES :
Spring Testing Support
TestNG Reference
Reference: Spring Testing Support with TestNG from our JCG partner Eren Avsarogullari at the Online Technology Vision blog.