Unit Testing The primary goal of unit testing is  to take  the smallest piece  of testable software,  isolate it   from the remainder of the code,  and determine whether it behaves  exactly as you expect .  by Bárbara Cabral Sofshore Software Engineering
Unit Testing What's important to know? The architecture of the system How to work with testing frameworks  How to write  good test-cases What is Good Unit Test? The test shall have a purpose to exist The test shall prioritize only the main problems, it means, the tester shall  think  about the better way to test the code.
TestNG TestNG is a testing framework inspired from JUnit and NUnit but introducing some new functionalities Writing a test is typically a three-step process: Write the business logic of your test and insert TestNG annotations in your code. Add the information about your test (e.g. the class name, the groups you wish to run, etc...) in a testng.xml file or in build.xml. Run TestNG.
TestNG package example1; import org.testng.annotations.*; public class SimpleTest { @BeforeClass public void setUp() { // code that will be invoked when this test is instantiated } @Test(groups = { "fast" }) public void aFastTest() { System.out.println("Fast test"); } @Test(groups = { "slow" }) public void aSlowTest() { System.out.println("Slow test"); } }
testng.xml <project default=&quot;test&quot;> <taskdef name=&quot; testng &quot; classpathref=&quot;cp&quot; classname=&quot; org.testng.TestNGAntTask &quot; /> <target name=&quot;test&quot;> <testng classpathref=&quot;cp&quot; groups=&quot; fast &quot;> <classfileset dir=&quot;build&quot; includes=&quot;example1/*.class&quot;/> </testng> </target> </project> <!DOCTYPE suite SYSTEM &quot;http://testng.org/testng-1.0.dtd&quot; > <suite name=&quot;Suite1&quot; verbose=&quot;1&quot; > <test name=&quot;Regression1&quot;  > <packages>   <package name=&quot;test.sample&quot; /> </packages> </test> </suite>
DBUnit DbUnit is a JUnit extension (also usable with Ant) targeted at database-driven projects that, among other things, puts your database into a known state between test runs. Best Pratices Use one database instance per developer Good setup don't need cleanup! Use multiple small datasets Connection management strategies
DBUnit Static data Testing can be simplified if you can get your database in a known state before a test is run.  For this, we have the sql files to build the database: tables, columns and static data (ex: Cities of the Belgium).  This kind of data rarely change! Dinamic data Most of your tests do not require the entire database to be re-initialized. So, instead of putting your entire database data in one large dataset, try to break it into many smaller  chunks . This reduces the overhead caused by initializing your database for each test. This also facilitates team development since many developers working on different components can modify datasets independently. We can be have one dataSet to each class or to each test or to each group of tests.  This kind of data is not commited in the database!
Strategy Run TestNG To create the static data To read the testng.xml file(s)
A very simple Unit Test class  User { private String name; public String getName() { return name; } public void setName(String newName) { name = newName; } } class  User Test  extends  TestSuite  { public void testNameProperty() { User user = new User(); assertNull(user.getName()); String testName = &quot;test&quot;; user.setName(testName); assertEquals(testName, user.getName()); } }
A very simple  Good  Unit Test public   class  TestUser { Role  userRole ; Role  developerRole ; @BeforeClass public   void  beforeClass()  throws  Exception { userRole  = UtilTestUser. getRole (RoleType. USER ); developerRole  = UtilTestUser. getRole (RoleType. DEVELOPER ); } /** *   1.   To   create   an   user   object   *   2.   Add   the   role(enum)   to   the   role   list   of   the   user   object   *   3.   Check   if   the   role   really   was   added *   @throws   InvalidNameException */ @Test (groups = {  &quot;API&quot;  }) public   void  testAddRole()  throws  InvalidNameException { User user = UserFactory. createUser ( &quot;asen&quot; ,  &quot;as12$as&quot; ,  &quot;Airton Senna&quot; ); user.addRole( userRole ); Assert. assertNotNull (user.getRoles()); Assert. assertEquals (user.getRoles().size(), 1); Assert. assertEquals (user.getRoles().iterator().next(),  userRole ); } Test Script
Example:   The Architecture of the User Management User <Interface>  The contract to manipulate the object User We need generate a TestUser UserDAO <Interface>  The contract to manipulate the object UserHibernateDAO The object UserHibernateDAO is responsible to provide a persistence layer to connect the object with the database UserManager <Interface>  The contract to manipulate the object DefaultUserManager The object DefaultUserManager is responsible to provide some services as to load an user by its logon identifier and to save a new user or to save the object user updated.
TestUserManager public   class  TestUserManager  extends  DBUnitTestCase { UserManager  userManager ; @BeforeClass public   void  beforeClass()  throws  Exception { userManager  = UtilTestUser. getTestUserManager (); } /** *   1.   A   new   user   with   an   existent   userId   is   created.   *   2.   The   user   is   saved   *   3.   A   UserIdExistsException   is   thrown */ @Test (groups = {  &quot;API&quot;  }, expectedExceptions = { UserAlreadyExistsException. class  }) public   void  saveUserWithTheSameUserIdCausesException() throws  InvalidNameException, UserAlreadyExistsException,  DataAccessException, ServiceException { User user1 = UserFactory. createUser ( &quot;gkue&quot; ,  &quot;as12$as&quot; ,  &quot;Gustavo Kuerten&quot; ); userManager .saveUser(user1); User user2 = UserFactory. createUser ( &quot;gkue&quot; ,  &quot;as12$as&quot; ,  &quot;Gustavo Kuerten&quot; ); userManager .saveUser(user2); }
The database unit test public   class  TestUser DAO  extends  DBUnitTestCase { private   static   final  String[]  TABLES_CHECK_USER  = { &quot;users&quot; ,  &quot;roles&quot; ,  &quot;user_roles&quot; }; //(...) --> a configuration code here /** *   1.The   object   user   shall   be   created   with   all   attributes   and   roles *   2.The   object   shall   be   saved   in   the   database *   3.The   dataSet   expected   shall   be   created   to   compare   against   the   user   object   stored */ @Test (groups={ &quot;database&quot; }) public   void  testSaveUser()  throws  InvalidNameException,  DatabaseUnitException, SQLException, IOException, UserAlreadyExistsException, DAOException, ServiceException { usesDataset( DATASET_BASE ); User user = UserFactory. createUser ( &quot;pcoe&quot; ,  &quot;pc910*pc&quot; ,  &quot;Paulo Coelho&quot; ); user.addRole( userRole ); user.addRole( adminRole ); userDao .saveUser(user); assertDataSet( &quot;saveUserExpected&quot; ,  TABLES_CHECK_USER ); }

Presentation Unit Testing process

  • 1.
    Unit Testing Theprimary goal of unit testing is to take the smallest piece of testable software, isolate it from the remainder of the code, and determine whether it behaves exactly as you expect . by Bárbara Cabral Sofshore Software Engineering
  • 2.
    Unit Testing What'simportant to know? The architecture of the system How to work with testing frameworks How to write good test-cases What is Good Unit Test? The test shall have a purpose to exist The test shall prioritize only the main problems, it means, the tester shall think about the better way to test the code.
  • 3.
    TestNG TestNG isa testing framework inspired from JUnit and NUnit but introducing some new functionalities Writing a test is typically a three-step process: Write the business logic of your test and insert TestNG annotations in your code. Add the information about your test (e.g. the class name, the groups you wish to run, etc...) in a testng.xml file or in build.xml. Run TestNG.
  • 4.
    TestNG package example1;import org.testng.annotations.*; public class SimpleTest { @BeforeClass public void setUp() { // code that will be invoked when this test is instantiated } @Test(groups = { &quot;fast&quot; }) public void aFastTest() { System.out.println(&quot;Fast test&quot;); } @Test(groups = { &quot;slow&quot; }) public void aSlowTest() { System.out.println(&quot;Slow test&quot;); } }
  • 5.
    testng.xml <project default=&quot;test&quot;><taskdef name=&quot; testng &quot; classpathref=&quot;cp&quot; classname=&quot; org.testng.TestNGAntTask &quot; /> <target name=&quot;test&quot;> <testng classpathref=&quot;cp&quot; groups=&quot; fast &quot;> <classfileset dir=&quot;build&quot; includes=&quot;example1/*.class&quot;/> </testng> </target> </project> <!DOCTYPE suite SYSTEM &quot;http://testng.org/testng-1.0.dtd&quot; > <suite name=&quot;Suite1&quot; verbose=&quot;1&quot; > <test name=&quot;Regression1&quot; > <packages> <package name=&quot;test.sample&quot; /> </packages> </test> </suite>
  • 6.
    DBUnit DbUnit isa JUnit extension (also usable with Ant) targeted at database-driven projects that, among other things, puts your database into a known state between test runs. Best Pratices Use one database instance per developer Good setup don't need cleanup! Use multiple small datasets Connection management strategies
  • 7.
    DBUnit Static dataTesting can be simplified if you can get your database in a known state before a test is run. For this, we have the sql files to build the database: tables, columns and static data (ex: Cities of the Belgium). This kind of data rarely change! Dinamic data Most of your tests do not require the entire database to be re-initialized. So, instead of putting your entire database data in one large dataset, try to break it into many smaller chunks . This reduces the overhead caused by initializing your database for each test. This also facilitates team development since many developers working on different components can modify datasets independently. We can be have one dataSet to each class or to each test or to each group of tests. This kind of data is not commited in the database!
  • 8.
    Strategy Run TestNGTo create the static data To read the testng.xml file(s)
  • 9.
    A very simpleUnit Test class User { private String name; public String getName() { return name; } public void setName(String newName) { name = newName; } } class User Test extends TestSuite { public void testNameProperty() { User user = new User(); assertNull(user.getName()); String testName = &quot;test&quot;; user.setName(testName); assertEquals(testName, user.getName()); } }
  • 10.
    A very simple Good Unit Test public class TestUser { Role userRole ; Role developerRole ; @BeforeClass public void beforeClass() throws Exception { userRole = UtilTestUser. getRole (RoleType. USER ); developerRole = UtilTestUser. getRole (RoleType. DEVELOPER ); } /** * 1. To create an user object * 2. Add the role(enum) to the role list of the user object * 3. Check if the role really was added * @throws InvalidNameException */ @Test (groups = { &quot;API&quot; }) public void testAddRole() throws InvalidNameException { User user = UserFactory. createUser ( &quot;asen&quot; , &quot;as12$as&quot; , &quot;Airton Senna&quot; ); user.addRole( userRole ); Assert. assertNotNull (user.getRoles()); Assert. assertEquals (user.getRoles().size(), 1); Assert. assertEquals (user.getRoles().iterator().next(), userRole ); } Test Script
  • 11.
    Example: The Architecture of the User Management User <Interface> The contract to manipulate the object User We need generate a TestUser UserDAO <Interface> The contract to manipulate the object UserHibernateDAO The object UserHibernateDAO is responsible to provide a persistence layer to connect the object with the database UserManager <Interface> The contract to manipulate the object DefaultUserManager The object DefaultUserManager is responsible to provide some services as to load an user by its logon identifier and to save a new user or to save the object user updated.
  • 12.
    TestUserManager public class TestUserManager extends DBUnitTestCase { UserManager userManager ; @BeforeClass public void beforeClass() throws Exception { userManager = UtilTestUser. getTestUserManager (); } /** * 1. A new user with an existent userId is created. * 2. The user is saved * 3. A UserIdExistsException is thrown */ @Test (groups = { &quot;API&quot; }, expectedExceptions = { UserAlreadyExistsException. class }) public void saveUserWithTheSameUserIdCausesException() throws InvalidNameException, UserAlreadyExistsException, DataAccessException, ServiceException { User user1 = UserFactory. createUser ( &quot;gkue&quot; , &quot;as12$as&quot; , &quot;Gustavo Kuerten&quot; ); userManager .saveUser(user1); User user2 = UserFactory. createUser ( &quot;gkue&quot; , &quot;as12$as&quot; , &quot;Gustavo Kuerten&quot; ); userManager .saveUser(user2); }
  • 13.
    The database unittest public class TestUser DAO extends DBUnitTestCase { private static final String[] TABLES_CHECK_USER = { &quot;users&quot; , &quot;roles&quot; , &quot;user_roles&quot; }; //(...) --> a configuration code here /** * 1.The object user shall be created with all attributes and roles * 2.The object shall be saved in the database * 3.The dataSet expected shall be created to compare against the user object stored */ @Test (groups={ &quot;database&quot; }) public void testSaveUser() throws InvalidNameException, DatabaseUnitException, SQLException, IOException, UserAlreadyExistsException, DAOException, ServiceException { usesDataset( DATASET_BASE ); User user = UserFactory. createUser ( &quot;pcoe&quot; , &quot;pc910*pc&quot; , &quot;Paulo Coelho&quot; ); user.addRole( userRole ); user.addRole( adminRole ); userDao .saveUser(user); assertDataSet( &quot;saveUserExpected&quot; , TABLES_CHECK_USER ); }