Saturday, December 31, 2011

JUnit 4 Vs TestNG

1. Annotation @Test is used in both JUnit4 and TestNG but from different class:
  1. import org.junit.Test; // JUnit 4
  2. ... or
  3. import org.testng.annotations.Test; // TestNG
  4. public class MyTestClass {
  5.     @Test
  6.     public void aTestMethod() throws ... { ... }
  7. }
2. According to Annotation Support:

FeatureJUnit 4TestNG
Test annotation@Test@Test
Run before all tests in this suite have run@BeforeSuite
Run after all tests in this suite have run@AfterSuite
Run before the test@BeforeTest
Run after the test@AfterTest
Run before the first test method that belongs to any of these groups is invoked@BeforeGroups
Run after the last test method that belongs to any of these groups is invoked@AfterGroups
Run before the first test method in the current class is invoked@BeforeClass@BeforeClass
Run after all the test methods in the current class have been run@AfterClass@AfterClass
Run before each test method@Before@BeforeMethod
Run after each test method@After@AfterMethod
Ignore test@ignore@Test(enbale=false)
Expected exception@Test(expected = ArithmeticException.class)@Test(expectedExceptions = ArithmeticException.class)
Timeout@Test(timeout = 1000)@Test(timeout = 1000)
3. Exception Test

It says what exception will throw from the unit test.
//JUnit4
  1. @Test(expected = ArithmeticException.class)  
  2.     public void divisionByZeroException() {  
  3.       int i = 1/0;
  4.     }
//TestNG
  1. @Test(expectedExceptions = ArithmeticException.class)  
  2.     public void divisionByZeroException() {  
  3.       int i = 1/0;
  4.     }
4. Ignore Test

It says how to ignore the unit test.
//JUnit
  1. @Ignore("Not Ready to Run")  
  2. @Test
  3. public void IgnoreTest() {  
  4.     System.out.println("Method is not ready yet");
  5. }
//TestNG
  1. @Test(enabled=false)
  2. public void IgnoreTest() {  
  3.     System.out.println("Method is not ready yet");
  4. }
5. Suite Test

It says how to bundle a few unit test and run together.
//JUnit4
The "@RunWith" and "@Suite" are use to run the suite test. The below class means both unit test "JunitTest1" and "JunitTest2" run together after "JunitTest3" executed. All the declaration is define inside the class.
  1. @RunWith(Suite.class)
  2. @Suite.SuiteClasses({
  3.         JunitTest1.class,
  4.         JunitTest2.class
  5. })
  6. public class JunitTest3 {
  7. }
//TestNG
XML file is use to run the suite test. The below XML file means both unit test “TestNGTest1” and “TestNGTest2” will run it together.
  1. <suite name="My test suite">
  2.   <test name="My test">
  3.     <classes>
  4.        <class name="example.test.TestNGTest1" />
  5.        <class name="example.test.TestNGTest2" />
  6.     </classes>
  7.   </test>
  8. </suite>
6. Dependency Test

It says which test will execute after what test. If the dependent method fails, then all subsequent tests will be skipped, not marked as failed.
//JUnit4
JUnit framework is focus on test isolation; it did not support this feature at the moment.
//TestNG
It use "dependOnMethods" to implement the dependency testing as following
  1. @Test
  2. public void testMethod1() {
  3.     System.out.println("This is method 1");
  4. }
  5. @Test(dependsOnMethods={"testMethod1"})
  6. public void testMethod2() {
  7.     System.out.println("This is method 2");
  8. }
7. Parameterized Test

It says how to pass parameters to an unit test dynamically.
//JUnit4
The "@RunWith" and "@Parameter" is use to provide parameter value for unit test, @Parameters have to return List[], and the parameter will pass into class constructor as argument.
  1. @RunWith(value = Parameterized.class)
  2. public class JunitTest {
  3.      private int number;
  4.      public JunitTest(int number) {
  5.         this.number = number;
  6.      }
  7.      @Parameters
  8.      public static Collection<Object[]> data() {
  9.        Object[][] data = new Object[][] { { 1 }{ 2 }{ 3 }{ 4 } };
  10.        return Arrays.asList(data);
  11.      }
  12.      @Test
  13.      public void pushTest() {
  14.        System.out.println("Parameterized Number is : " + number);
  15.      }
  16. }
It has many limitations here; we have to follow the “JUnit” way to declare the parameter, and the parameter has to pass into constructor in order to initialize the class member as parameter value for testing. The return type of parameter class is “List []”, data has been limited to String or a primitive value for testing.
//TestNG
XML file or “@DataProvider” is used to provide vary parameter for testing.
(see the post: Parameterized Test TestNG and observe the difference)

Parameterized Test TestNG

Sometimes in TestNG test we need various parameter values for the unit test,we call the test as 'Parameterized Test'.
In TestNG there are two ways by which we can pass parameters to a test.They are,
  1. By TestNG's XML configuration files(testng.xml)
  2. By @DataProvider
1.By TestNG's XML configuration files(testng.xml):

Declare "@Parameters" annotation in method which needs parameter testing, the parametric data will be provide by testng.xml(TestNG's XML configuration files). By doing this, you can reuse a single test case with different data sets easily. In addition, even end user, QA can provide their own data sets for testing.
//TestNGParameterizedTest
  1. package example.test;
  2. import org.testng.annotations.*;
  3. /**
  4.  * TestNG Parameterized Test
  5.  *
  6.  */
  7. public class TestNGParameterizedTest {
  8.     @Test
  9.     @Parameters(value="input")
  10.     public void parameterTest(int input) {
  11.        System.out.println("Parameterized input is : " + input);
  12.     }
  13. }
//testng.xml
  1. <suite name="My test suite">
  2.   <test name="Parameterized test">
  3.     <parameter name="input" value="7"/>      
  4.     <classes>
  5.        <class name="example.test.TestNGParameterizedTest" />
  6.     </classes>
  7.   </test>
  8. </suite>
2 .By @DataProvider:

In the 1st way,while pulling data values into an XML file can be quite handy, but test cases occasionally may require complex data types, which can’t be represented as a String or a primitive value in XML file. TestNG handles this scenario with "@DataProvider" annotation, which facilitates the mapping of complex parameter types to a test method.
//CharASCII.java
  1. package sourse;
  2. public class CharASCII {
  3.    
  4.     public static int CharToASCII(final char character){
  5.         return (int)character;
  6.     }
  7.     public static char ASCIIToChar(final int ascii){
  8.         return (char)ascii;    
  9.     }
  10. }
//CharASCIITest.java
  1. package example.test;
  2. import org.testng.*;
  3. import org.testng.annotations.DataProvider;
  4. import org.testng.annotations.Test;
  5. import sourse.CharASCII;
  6. public class CharASCIITest  {
  7.     @DataProvider
  8.     public Object[][] ValidDataProvider() {
  9.         return new Object[][]{ { 'A'65 },{ 'B'66 },{ 'C'67 },{ 'D'68 },  { 'Z'90 } };
  10.     }
  11.     @Test(dataProvider = "ValidDataProvider")
  12.     public void CharToASCIITest(final char character, final int ascii) {
  13.         System.out.println("ASCII of "+character+" is "+ascii);
  14.         int result = CharASCII.CharToASCII(character);
  15.         Assert.assertEquals(result, ascii);
  16.     }
  17.     @Test(dataProvider = "ValidDataProvider")
  18.     public void ASCIIToCharTest(final char character, final int ascii) {
  19.         System.out.println("Char of "+ascii+" is "+character);
  20.         char result = CharASCII.ASCIIToChar(ascii);
  21.         Assert.assertEquals(result, character);
  22.     }  
  23. }