반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

JUnit 4 와 TestNG 비교하기

2013. 11. 3. 23:51 | Posted by 솔웅


반응형

JUnit 4 Vs TestNG – Comparison


JUnit 4 와 TestNG는 자바에서 유닛 테스트 프레임워크로는 아주 유명합니다. 이 둘은 기능적인 면에서 아주 비슷합니다. 어느것이 더 좋을까요? 현재 참여중인 자바 프로젝트에서 어떤 프레임워크를 사용해야 할 까요?


아래 JUnit 4와 TestNG를 기능적으로 비교해 봤습니다.





1. Annotation Support

annotation 을 지원하는 것은 JUnit 4나 TestNG 모두 비슷하게 사용하고 있습니다.


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)


JUnit 4와 TestNG 사이에서 사용하는 annotation의 차이점은 아래와 같습니다.


1. In JUnit 4, we have to declare “@BeforeClass” and “@AfterClass” method as static method. TestNG is more flexible in method declaration, it does not have this constraints.


2. 3 additional setUp/tearDown level: suite and group (@Before/AfterSuite, @Before/AfterTest, @Before/AfterGroup). See more detail here.


JUnit 4

    @BeforeClass
    public static void oneTimeSetUp() {
        // one-time initialization code   
    	System.out.println("@BeforeClass - oneTimeSetUp");
    }


TestNG

    @BeforeClass
    public void oneTimeSetUp() {
        // one-time initialization code   
    	System.out.println("@BeforeClass - oneTimeSetUp");
}



JUnit 4에서는 annotation 이름이 약간 불명확 합니다. Befor, After, Expected 는 정확히 무엇을 의미하는지 그 이름만으로 파악하기 힘듭니다. 반면에 TestNG는 BeforeMethod, AfterMethod, ExpectedException 을 사용해서 이름만 듣고 어떤 의미인지 파악이 가능합니다.



2. Exception Test


exception testing 이란 해당 단위테스트에서 throw될 예외가 어떤 것인지 설정해서 테스트해 볼 수 있다는 것을 말합니다. 이 기능은 JUnit 과 TestNG 모두에 있습니다.



JUnit 4

      @Test(expected = ArithmeticException.class)  
	public void divisionWithException() {  
	  int i = 1/0;
	}


TestNG

      @Test(expectedExceptions = ArithmeticException.class)  
	public void divisionWithException() {  
	  int i = 1/0;
	}


3. Ignore Test


Ignored 는 단위테스트를 실행하지 않도록 하는 겁니다. 이것도 두 프레임워크 모두에서 지원합니다.


JUnit 4

        @Ignore("Not Ready to Run")  
	@Test
	public void divisionWithException() {  
	  System.out.println("Method is not ready yet");
	}


TestNG

	@Test(enabled=false)
	public void divisionWithException() {  
	  System.out.println("Method is not ready yet");
	}


4. Time Test

Time Test는 단위 테스트를 시행하는 시간이 특정 시간 보다 더 걸리게 되면 테스트를 fail로 처리하도록 하는 기능입니다. 이것도 두 프레임워크 모두에서 지원합니다.


JUnit 4

        @Test(timeout = 1000)  
	public void infinity() {  
		while (true);  
	}



TestNG

	@Test(timeOut = 1000)  
	public void infinity() {  
		while (true);  
	}


5. Suite Test


Suite Test는 여러개의 단위 테스트를 묶어서 실행하는 것을 말합니다. 이 기능도 두 프레임워크 모두에서 사용하고 있습니다. 하지만 그 사용법은 많이 다릅니다.


JUnit 4


The “@RunWith” and “@Suite” are use to run the suite test. The below class means both unit test “JunitTest1” and “JunitTest2” run together after JunitTest5 executed. All the declaration is define inside the class.


@RunWith(Suite.class)
@Suite.SuiteClasses({
        JunitTest1.class,
        JunitTest2.class
})
public class JunitTest5 {
}


TestNG


TestNG에서는 XML 파일이 사용됩니다. 아래 XML 파일은 TestNGTest1과 TestNGTest2를 같이 테스트하기 위해 만든 겁니다.

<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="My test suite">
  <test name="testing">
    <classes>
       <class name="com.fsecure.demo.testng.TestNGTest1" />
       <class name="com.fsecure.demo.testng.TestNGTest2" />
    </classes>
  </test>
</suite>



TestNG는 bundle class testing 이외의 것에도 활용할 수 있습니다. 물론 단위테스트를 bundle로 실행하는데도 사용할 수 있구요. TestNG에는 Grouping이라는 개념이 있습니다. 각 메소드들은 그룹에 속해 있습니다. 이렇게 함으로서 기능별로 테스트들을 카테고리로 만들 수 있습니다.

예를 들어 아래 예제를 보시면 3개의 그룹에 4개의 메소드를 포함하고 있는 한개의 클래스를 사용하는 방법을 보여 줍니다.

        @Test(groups="method1")
	public void testingMethod1() {  
	  System.out.println("Method - testingMethod1()");
	}  
 
	@Test(groups="method2")
	public void testingMethod2() {  
		System.out.println("Method - testingMethod2()");
	}  
 
	@Test(groups="method1")
	public void testingMethod1_1() {  
		System.out.println("Method - testingMethod1_1()");
	}  
 
	@Test(groups="method4")
	public void testingMethod4() {  
		System.out.println("Method - testingMethod4()");
	}


With the following XML file, we can execute the unit test with group “method1” only.

<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="My test suite">
  <test name="testing">
  	<groups>
      <run>
        <include name="method1"/>
      </run>
    </groups>
    <classes>
       <class name="com.fsecure.demo.testng.TestNGTest5_2_0" />
    </classes>
  </test>
</suite>


Grouping이라는 개념을 사용하면 integration test도 가능하도록 합니다. 예를 들어 단위 테스트 클래스들 중 DatabaseFunction 그룹만 따로 테스트하는 일 등이 가능합니다.


6. Parameterized Test


Parameterized Test는 단위 테스트에 파라미터 값을 사용한다는 것입니다. 이 기능두 두 프레임워크 모두 사용하고 있습니다. 하지만 그 사용법은 많이 다릅니다.


JUnit 4


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.


@RunWith(value = Parameterized.class)
public class JunitTest6 {
 
	 private int number;
 
	 public JunitTest6(int number) {
	    this.number = number;
	 }
 
	 @Parameters
	 public static Collection<Object[]> data() {
	   Object[][] data = new Object[][] { { 1 }, { 2 }, { 3 }, { 4 } };
	   return Arrays.asList(data);
	 }
 
	 @Test
	 public void pushTest() {
	   System.out.println("Parameterized Number is : " + number);
	 }
}


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 파일을 사용하거나 @DataProvider 를 사용해서 parameterized test를 수행할 수 있습니다.


XML file for parameterized test.


Only “@Parameters” declares in method which needs parameter for testing, the parametric data will provide in TestNG’s XML configuration files. By doing this, we can reuse a single test case with different data sets and even get different results. In addition, even end user, QA or QE can provide their own data in XML file for testing.


Unit Test

      public class TestNGTest6_1_0 {
 
	   @Test
	   @Parameters(value="number")
	   public void parameterIntTest(int number) {
	      System.out.println("Parameterized Number is : " + number);
	   }
 
      }


XML File

<!DOCTYPE suite SYSTEM "http://beust.com/testng/testng-1.0.dtd" >
<suite name="My test suite">
  <test name="testing">
 
    <parameter name="number" value="2"/> 	
 
    <classes>
       <class name="com.fsecure.demo.testng.TestNGTest6_0" />
    </classes>
  </test>
</suite>


@DataProvider for parameterized test.


While pulling data values into an XML file can be quite handy, tests occasionally require complex types, which can’t be represented as a String or a primitive value. TestNG handles this scenario with its @DataProvider annotation, which facilitates the mapping of complex parameter types to a test method.

@DataProvider for Vector, String or Integer as parameter

        @Test(dataProvider = "Data-Provider-Function")
	public void parameterIntTest(Class clzz, String[] number) {
	   System.out.println("Parameterized Number is : " + number[0]);
	   System.out.println("Parameterized Number is : " + number[1]);
	}
 
	//This function will provide the patameter data
	@DataProvider(name = "Data-Provider-Function")
	public Object[][] parameterIntTestProvider() {
		return new Object[][]{
				   {Vector.class, new String[] {"java.util.AbstractList", 
"java.util.AbstractCollection"}},
				   {String.class, new String[] {"1", "2"}},
				   {Integer.class, new String[] {"1", "2"}}
				  };
	}


@DataProvider for object as parameter


P.S “TestNGTest6_3_0” is an simple object with just get set method for demo.

        @Test(dataProvider = "Data-Provider-Function")
	public void parameterIntTest(TestNGTest6_3_0 clzz) {
	   System.out.println("Parameterized Number is : " + clzz.getMsg());
	   System.out.println("Parameterized Number is : " + clzz.getNumber());
	}
 
	//This function will provide the patameter data
	@DataProvider(name = "Data-Provider-Function")
	public Object[][] parameterIntTestProvider() {
 
		TestNGTest6_3_0 obj = new TestNGTest6_3_0();
		obj.setMsg("Hello");
		obj.setNumber(123);
 
		return new Object[][]{
				   {obj}
		};
	}



TestNG의 parameterized test는 사용자 편의적이고 아주 유연합니다. (XML 파일을 사용할 수도 있고 클래스 내에서 선언할 수도 있습니다.) 또한 파라미터로서 여러 데이터 타입을 사용할 수 있습니다. 위 예제에서 볼 수 있듯이 우리가 만든 object(TestNGTest6_3_0)도 pass 할 수 있습니다.


7. Dependency Test


The “Parameterized Test” means methods are test base on dependency, which will execute before a desired method. If the dependent method fails, then all subsequent tests will be skipped, not marked as failed.


JUnit 4


JUnit 프레임워크는 단위 테스트에만 촛점이 맞춰져 있습니다. 이 Dependency Test에 대해서는 아직 기능을 제공하지 않고 있습니다.


TestNG


TestNG에서는 dependency testiong을 사용하기 위해 dependOnMethods를 사용합니다.

        @Test
	public void method1() {
	   System.out.println("This is method 1");
	}
 
	@Test(dependsOnMethods={"method1"})
	public void method2() {
		System.out.println("This is method 2");
	}



method2() 는 method1()이 성공했을 때만 실행됩니다. 


Conclusion

이 두 프레임워크의 기능을 모두 비교해 보고 난 후 저는 자바 프로젝트에 사용할 core unit test framework로 TestNG를 사용할 것을 권장합니다. 왜냐하면 TestNG는 좀 더 발전된 parameterized testing, dependency testing 그리고 suite testing (Grouping concept)를 지원하기 때문입니다. TestNG is meant for high-level testing and complex integration test.

TestNG의 유연성은 더 규모가 큰 test suites를 효과적으로 수행할 수 있도록 도와 줍니다. 또한 TestNG는 core JUnit 4 기능을 모두 cover 합니다. 저는 더 이상 JUnit을 사용할 이유를 찾을 수가 없네요.

References

TestNG
————
http://en.wikipedia.org/wiki/TestNG
http://www.ibm.com/developerworks/java/library/j-testng/
http://testng.org/doc/index.html
http://beust.com/weblog/

JUnit
———–
http://en.wikipedia.org/wiki/JUnit
http://www.ibm.com/developerworks/java/library/j-junit4.html
http://junit.sourceforge.net/doc/faq/faq.htm
http://www.devx.com/Java/Article/31983/0/page/3
http://ourcraft.wordpress.com/2008/08/27/writing-a-parameterized-junit-test/

TestNG VS JUnit
——————
http://docs.codehaus.org/display/XPR/Migration+to+JUnit4+or+TestNG
http://www.ibm.com/developerworks/java/library/j-cq08296/index.html
http://www.cavdar.net/2008/07/21/junit-4-in-60-seconds/



반응형