everydayminder

learn something everyday

Posts Tagged ‘unit test

JUnit으로 test coverage를 높이는 습관

leave a comment »

“우리나라 정서상 어렵다, 현실에 맞지 않다”는  말들을 하기도 하고, 듣기도 한다.

Rod Johson이 그의 저서 “Expert one-on-one J2EE Design and Development”에서
XP 기법을 소개하면서, 그 기법의 모든 것을 따르지는 않더라도 테스트 지향 개발 방법은 바람직하다고 하였다.

테스트에 대한 XP의 기법은,

  • 코드를 작성하기 전에 먼저 테스트 코드를 작성하자
  • 모든 코드는 단위 테스트 코드를 가져야 하고, 각 단위 테스트는 자동으로 실행될 수 있어야 한다.
  • 버그가 발견되면 버그를 고치기에 앞서, 버그를 다시 재현해 내는 테스트 케이스를 정의한 후에 고쳐야 한다.

테스트 코드를 먼저 작성하는 것이 더 유용하다는 관점에 대해서는,

  • 테스트 문서는 스펙 문서에 근거할 뿐만 아니라, 부가적인 정보를 제공한다.
  • 클래스나 컴포넌트 자체로만으로는 불확실한 내용이 테스트에서는 명확해진다. (사용처나 목적을 분명히 알고 작성할 것이므로)
  • 사실, 코드를 모두 작성한 후에 별도로 테스트 코드를 작성하는 것이 훨씬 어렵다.

그러므로, 한 메소드씩 작성하되, 코드-테스트코드의 순서가 아니라, 반대인 테스트코드-코드의 순서로 작성해 나가자.

Rod Jonhson은 test 메소드의 이름을 다음과 같이 작성하도록 권고한다.

test<Method to be tested><Description of test>

예를 들면,

private void testCommaDelimitedListToStringArrayLegalMatch(String[] components);
public void testCommaDelimitedListToStringArrayMatchWords();
public void testCommaDelimitedListToStringArraySingleString();

단순히 테스트의 coverage를 높이기 보다는, 테스트의 메소드 이름만으로도 테스트의 성격을 알 수 있도록 작성해 보자.
테스트내에서도 반복되는 테스트의 경우 private로 작성하고, 이를 활용하자.

위의 예는,

commaDelimitedListToStringArray(String s);

를  테스트한 예이다.

그리고, 테스트코드도 꾸준히 버전 관리를 해야 한다.

Written by everydayminder

August 1, 2010 at 15:33

Posted in java

Tagged with , , ,

python class의 메소드별 단위 테스트 (unittest pyUnit vs py.test)

with one comment

여러가지 단위 테스트 프로그램이 존재하나,
그 중, standard library로 포함되어 있는 pyUnit (unittest) 과 py.test를 비교하여 간략하게
비교한다.

ㅁ 테스트를 위한 클래스

class A:
    def getA(self):
        return ‘a’

    def getWrongA(self):
        return ‘b’

if __name__ == ‘__main__’:
    aa = A()
    print aa.getA()

* 위의 코드에서 보는 바와 같이, 테스트 메소드는 두 개(getA와 getWrongA)이다.
* 각 메소드는 정상 상황(‘a’를 리턴할 것이라 예상하는 상황에서 실제로 ‘a’를 리턴)과 오류 상황(‘a’를 리턴할 것이라 예상하는 상황에서 실제로는 ‘a’가 아닌 다른 값을 리턴)을 나타낸다.

ㅁ 설치 방법
  1. pyUnit : 별도의 설치 과정 불필요
  2. py.test : 별도의 설치 과정 필요 (http://pypi.python.org/pypi/py 참고)

ㅁ 테스트 코드 작성 방법
   1. pyUnit

from a import A

import unittest

class ATester(unittest.TestCase):
    def setUp(self):
        print ‘setUp called..’
        self.aa = A()

    def testGetA(self):
        print ‘testGetA..’
        self.assertEquals(self.aa.getA(), ‘a’)

    def testGetWrongA(self):
        print ‘testGetWrongA..’
        self.assertEquals(self.aa.getWrongA(), ‘a’)

    def tearDown(self):
        print ‘tearDown called..’

if __name__ == ‘__main__’:
    testSuite = unittest.TestSuite()
    for testmethod in (‘testGetA’, ‘testGetWrongA’):
        testSuite.addTest(ATester(testmethod))

    runner = unittest.TextTestRunner()
    runner.run(testSuite)


   2. py.test

from a import A

def test_getA():
    aa = A()
    assert aa.getA() == ‘a’

def test_getWrongA():
    aa = A()
    assert aa.getWrongA() == ‘b’

ㅁ 실행 방법
  1. pyUnit

python test_with_unittest.py  (위의 예제 파일 이름이 test_with_unittest.py임)

  2. py.test

py.test (이름 지정하지 않아도 찾아서 테스트 실시)

ㅁ 실행 결과
1. pyUnit

setUp called..
testGetA..
tearDown called..
.setUp called..
testGetWrongA..
FtearDown called..

======================================================================
FAIL: testGetWrongA (__main__.ATester)
———————————————————————-
Traceback (most recent call last):
  File “test_with_unittest.py”, line 16, in testGetWrongA
    self.assertEquals(self.aa.getWrongA(), ‘a’)
AssertionError: ‘b’ != ‘a’

———————————————————————-
Ran 2 tests in 0.000s

FAILED (failures=1)

2. py.test

================================ test process starts ================================
executable:   /usr/bin/python  (2.5.2-final-0)
using py lib: /root/jhkim/lib/py-0.9.2/py <rev unknown>

test_with_py.py[2] .F

======================================================================================
________________________________entrypoint: test_getWrongA _____________________________
    def test_getWrongA():
        aa = A()
E       assert aa.getWrongA() == ‘a’
>       assert ‘b’ == ‘a’
         +  where ‘b’ = <a.A instance at 0x838392c>.getWrongA()

/root/test/test_with_py.py:9: AssertionError
_______________________________________________________________________________________
tests finished: 1 passed, 1 failed in 0.18 seconds ========================================================

 사용 목적이나 규모에 따라, 사용자 기호에 따라 각각 장단점이 존재한다!

Written by everydayminder

February 12, 2009 at 05:04

Posted in python

Tagged with , , , ,