manywaypark's Blog
개발, 검색, 함수

문제:
python에서 unittest 모듈을 써서 unit test를 할 때 다음과 같이 썼다.

if __name__ == '__main__':
unittest.main()


수행하면 다음과 같이 테스트케이스 다 실행하고 OK 뜬 후에 exception이 났다. 좀 찜찜했다.

......
......
Ran 2 tests in 12.545s

OK
Exception in thread "main" Traceback (most recent call last):
  File "D:\comms_share\csm-gui-test\sikuli\csmLogin.sikuli\csmLogin.py", line 11
1, in <module>
    unittest.main()
  File "D:\comms_share\csm-gui-test\sikuli-script.jar\Lib\unittest.py", line 768
, in __init__
  File "D:\comms_share\csm-gui-test\sikuli-script.jar\Lib\unittest.py", line 806
, in runTests
SystemExit: False


해결:
여기저기 뒤져봤더니 IDLE 문제라고 이미 알려져있었다.
다음과 같이 쓰면 된다.

class FooTest(unittest.TestCase) :
def setUp(self) :
......
def tearDown(self):
......
def testSomething() :
......

if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(FooTest)  
unittest.TextTestRunner(verbosity=2).run(suite)


python 버전 정보는 다음과 같다

Python 2.6.5 (r265:79063, Jun 12 2010, 17:07:01)
[GCC 4.3.4 20090804 (release) 1] on cygwin


refs:
좀 복잡한 테스트 케이스를 하나 추가하고 컴파일후 mod:test()를 실행했더니,
다음과 같은 에러가 나면서 그 모듈에 대한 유닛 테스트가 아예 동작하지 않았다.
*** test module not found ***
::false

{error,{module_not_found,false}}

순간 당황했으나, 방금 추가한 테스트 케이스를 살펴보니 _assert macro에 들어가는 내용이 잘못되어 있었다. boolean expression이 들어가야하는 곳에 그냥 expression만 하나 들어있었고, _assert(very_complex_expression) =:= expected value의 형태로 되어 있었다(어제 급히 추가하고 안돌려보고 바로 퇴근한 것이 후회되는 순간이었다). 그래도 컴파일은 멀쩡히 평소처럼 잘 되고 runtime에 가서야 에러가 나는 것은 좀 불편해보인다.

간략히 축약해서 예를 들자면 다음과 같다.
%% causes runtime error (see above msg).
?_assert(1+1) =:= 2
%% runs well w/o runtime error (good)
?_assert(1+1 =:= 2)

실제 내 코드에서는 1+1부분이 많이 복잡해서 화면을 넘어가고 있었고, _assert macro가 여러 개의 리스트로 묶여져 있어서 찾는데 좀 고생했다. Orz.

happy hackin'
일단 eunit으로 테스트를 하는 것을 가정한다.

unit test - makefile에서...
make file에 다음과 같은 부분을 추가한 후에, make test 하면 간편하게 명령행에서 unit test를 수행할 수있다.
(makefile 뼈대는 Programming Erlang을 기초로 했다.)

......
MODS = doc str_util db i18n tiny_scan
......

test: compile test_subdirs
    rm -rf Mnesia.nonode@nohost # removes previous mneisa db (optional).
    @for m in ${MODS};\
    do \
        echo "testing $$m";\
        ${ERL} -noshell -pz "subdir1" -pz "subdir2" -s $$m test -s init stop;\
    done

test_subdirs:
    cd subdir1; make test
    cd subdir2; make test

unit test, coverage test - 개발중 REPL(distel 또는 erl prompt) 에서...
REPL을 사용해서 (멋지게) 코딩-테스트를 반복중이라면, 다음과 같은 모듈을 하나 디렉토리에 넣어서 test:unit() 또는 test:cover() 를 실행시켜서 unit test 및 coverage test를 시시때때로 수행해 볼 수 있다.


테스트는 아무리 강조해도 지나치지 않다.
경험상 대부분의 버그는 테스트되지 않거나, 적절하지 못한 테스트(셋)들을 통과한 코드에 기생한다.

happy hackin'



erlang의 one-time assignment를 이용한 간단한 리팩토링에 관해서 설명한다.

erlang에서의 변수 특성:
  1. erlang은 변수에 값(value)를 한번만 할당(assign)할 수 있다.
  2. 한번 값이 할당된 변수는 이전과 동일한 값을 할당하지 않으면 에러가 난다.

확인:
(emacs@desktop)54> Foo = 1.
1
(emacs@desktop)55> Foo = 1.
1
(emacs@desktop)56> Foo = 2.
** exception error: no match of right hand side value 2

리팩토링은 보통 코드의 결과는 그대로 유지하면서 내부를 개선하는 것으로 정의된다.

변수 특성을 이용한 리팩토링 절차:
  1. 리팩토링할 함수를 정한다.
  2. 함수의 결과값을 변수에 저장한다. (적절한 인자를 줄 수도 있다)
  3. 함수 리팩토링 & 컴파일
  4. 같은 변수에 새 함수의 결과값을 대입해본다.
  5. 에러 체크.

간단한 함수의 경우는 이 방법이 별 필요가 없을 수도 있지만, 수백 수천개의 list element들을 결과로 리턴하는 경우에는 꽤나 유용하다.

각각 다른 변수(Before, After)에 대입해서 =:= 연산자로 비교할 수도 있겠지만, 그냥 같은 변수에 대입해 보는 것이 조금 더 편하다. (자연스런 REPL loop + history 기능 활용)

물론 여기서 설명한 것은 간단히 빨리 테스트해보아야할 경우를 위한 것이다. 실제 제품개발에는 eunit같은 unit test tool을 적용해 조직화된 테스트셋을 구성해야한다.

happy hackin'

1 
분류 전체보기 (306)
잡담 (20)
함수형 언어 (65)
emacs (16)
java (18)
tips & tricks (154)
사랑 (1)
가사 (0)
독서 (4)
mobile (6)
비함수형 언어 (2)

공지사항

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

04-21 01:27