2011-02-01 4 views
5

저는 파이썬을 사용하는 초보 프로그래밍 학년입니다. 파이썬 - 푸 (python-fu)는 그다지 강하지 못하지만 일부 등급을 자동화하려고합니다.input()을 사용하는 초보 학생 Python 프로그램을 테스트하려면 어떻게해야합니까 (unittest?)?

온라인으로 보면 PyUnit 테스트 스위트가 마음에 들지만, 내가 원하는 것보다 조금 힘이 듭니다.

제 문제는 학생의 기능에 원하는 테스트 입력을 전달하는 방법이 확실하지 않습니다. 명령 줄 인수 나 여러 기능을 아직 사용하지 않았으므로 input() 함수를 통해 사용자 입력을 받고 있기 때문입니다.

바보 예 : 내 어리석은 예를 들어

#/usr/bin/python3.1 
# A silly example python program 
def main(): 
    a = int(input("Enter an integer: ")) 
    b = int(input("Enter another integer: ")) 
    c = a+b 
    print("The sum is %d" % c) 

if __name__ == '__main__' 
    main() 

, 나는 여러 가지 다른 입력에 대해 출력을 확인할 수 있습니다 단위 테스트를 작성 얼마나? (즉, 입력에 2와 3을 전달하면 출력 문자열은 "합계가 5"여야합니다.)

+0

두 개의 입력 행에 오른쪽 괄호가 없습니다. – Javier

+0

@Javier : 수정 됨. 고마워, 누군가 내 질문을 편집하고'eval (''을 추가했지만 상대방을 닫지는 않았다.) – Jason

답변

8

편집 : 예는 unittest가 아니기 때문에 제안하십시오. 초보자 학생들은 단지 제약 조건에 혼란스러워 할 것입니다.)

찾고있는 것과 일치하는 출력에만 관심이 있다면, 왜 "바보 같은"bash를 사용하지 않는 것이 좋을까요? 같은 뭔가 :

echo -e "2\n3" | python test.py | grep -q "The sum is 5" && echo "Success" 

이 같은 상대적으로 사소한 프로그램을 수행하는 경우, 다음이 약간의 노력을 필요로하는 충분한, 또는 충분히 좋은 해결책이 될 것이다.

+0

이것은 실제로 나에게 가장 유용하다. 당신이 테스트 할 수있는 프로그램을 만드는 것이 학생들이 가르쳐 준 것 (그것은 매우 intro 수준의 클래스입니다.) 그러나 이것과 같은 것이 실제로 가장 좋을 것입니다. – Jason

+0

@ Jason - 응답하기 전에 질문을 더 자세히 읽어야합니다. * 한숨 * – Omnifarious

4

정말 단위 테스트 할 수 없습니다. 단위 테스트 작성에 관한 한 가지 중 하나는 종종 단위 테스트를 위해 코드를 다르게 작성해야한다는 것입니다. 따라서이 경우 별도의 함수로 호출하기 위해 호출을 분석해야합니다. 그러면이를 패치 할 수 있습니다.

def my_input(prompt): 
    return input(prompt) 

def main(): 
    a = int(eval(my_input("Enter an integer: ")) 

등 이제 테스트 캔 원숭이 패치 myscript.my_input 원하는 값을 반환합니다.

+0

테스트 해 보니 주셔서 감사합니다. 내가 읽은 것의 맥락에서 많은 의미. – Jason

2

echo과 함께 제공 될 수있는 명령 줄 프로그램보다 복잡한 상호 작용이 필요한 경우 expect을 볼 수 있습니다. docs 가입일

2

는 :

개체가 sys.stdin

, sys.stdout 및 sys.stderr를 은 인터프리터의 표준 입력, 출력 및 오류 스트림에 대응 객체를 파일로 초기화된다.

이렇게이 논리를 따르는 경우 작동합니다.당신의 필수 입력으로 파일을 만듭니다

$ cat sample_stdin.txt 
hello 
world 

그런 다음 해당 파일을 가리 키도록 sys.stdin 리디렉션 :

#!/usr/bin/env python 
import sys 

fh = open('sample_stdin.txt', 'r') 
sys.stdin = fh 

line1 = raw_input('foo: ') 
line2 = raw_input('bar: ') 

print line1 
print line2 

출력 :

$python redirecting_stdin.py 
foo: bar: hello 
world 
2

짧은 대답, 그렇게하지 않습니다. 테스트 가능성을 위해 디자인해야합니다. 이는 시스템 자원에 대한 대화에 사용할 인터페이스를 제공하는 간단한 방법을 제공하여 테스트 할 때 해당 인터페이스의 대체 구현을 제공 할 수 있음을 의미합니다.

다른 답변에 설명 된 원숭이 패치 솔루션이 효과가 있지만 가장 기본적인 옵션입니다. 개인적으로, 나는 사용자 상호 작용을위한 인터페이스 클래스를 작성할 것이다. 예를 들면 다음과 같습니다.

그러면 사용자와 이야기해야하는 항목은 클래스의 인스턴스를 생성자 또는 함수 인수로 가져올 수 있습니다. 기본 구현은 실제 input 함수를 호출 할 수 있지만 샘플 입력을 제공하거나 출력을 버퍼하여 검사 할 수 있도록 테스트에 사용되는 버전이 있습니다.

이것이 사실상 싱글 톤을 싫어하는 이유입니다 (어쨌든 파이썬에서 실제로 효과적으로 구현할 수는 없습니다). 테스트를 위해 스텁 버전으로 스텁 될 수없는 전역 적으로 액세스 가능한 인스턴스를 만들어 테스트 능력을 파괴합니다.

0

input 함수를 조롱하여 테스트 환경의 입력을 제공 할 수 있습니다.

작동하는 것처럼 보입니다. 그것은 테스트되지 않았습니다.

class MockInput(object): 
    def __init__(self, *values): 
     self.values= list(values) 
     self.history= [] 
    def __call__(self, *args, **kw): 
     try: 
      response= self.values.pop(0) 
      self.history.append((args, kw, response)) 
      return response 
     except IndexError: 
      raise EOFError() 

class TestSomething(unittest.TestCase): 
    def test_when_input_invalid(self): 
     input= MockInput("this", "and", "that") 
     # some test case based on the input function 
0

sys.stdin을 StringIO (또는 cStringIO) 개체로 바꿉니다.

2

나의 제안은 파이썬은 단위 테스트를 위해 제공하는 두 개의 프레임 워크 중 하나를 사용하여 코드를 리팩토링하는 것입니다 유닛 테스트 (일명 PyUnit) 및 doctest가.

이 사용 예이다 유닛 테스트 :

import unittest 

def adder(a, b): 
    "Return the sum of two numbers as int" 
    return int(a) + int(b) 

class TestAdder(unittest.TestCase): 
    "Testing adder() with two int" 
    def test_adder_int(self): 
     self.assertEqual(adder(2,3), 5) 

    "Testing adder() with two float" 
    def test_adder_float(self): 
     self.assertEqual(adder(2.0, 3.0), 5) 

    "Testing adder() with two str - lucky case" 
    def test_adder_str_lucky(self): 
     self.assertEqual(adder('4', '1'), 5) 

    "Testing adder() with two str" 
    def test_adder_str(self): 
     self.assertRaises(ValueError, adder, 'x', 'y') 

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

그리고이 사용 예 doctest가이다 I 입력을 사용하는 또 다른 예를 제조 doctest가 함께

# adder.py 

def main(a, b): 
    """This program calculate the sum of two numbers. 
    It prints an int (see %d in print()) 

    >>> main(2, 3) 
    The sum is 5 

    >>> main(3, 2) 
    The sum is 5 

    >>> main(2.0, 3) 
    The sum is 5 

    >>> main(2.0, 3.0) 
    The sum is 5 

    >>> main('2', '3') 
    Traceback (most recent call last): 
     ... 
    TypeError: %d format: a number is required, not str 
    """ 
    c = a + b 
    print("The sum is %d" % c) 

def _test(): 
    import doctest, adder 
    return doctest.testmod(adder) 

if __name__ == '__main__': 
    _test() 

() (파이썬 3을 사용하고 있다고 가정합니다.X) :

# adder_ugly.py 

def main(): 
    """This program calculate the sum of two numbers. 
    It prints an int (see %d in print()) 

    >>> main() 
    The sum is 5 
    """ 
    a = int(input("Enter an integer: ")) 
    b = int(input("Enter another integer: ")) 
    c = a+b 
    print("The sum is %d" % c) 


def _test(): 
    import doctest, adder_ugly 
    return doctest.testmod(adder_ugly) 

if __name__ == '__main__': 
    _test() 
나는 위의 -v 옵션을 예로 언급 된 각 실행됩니다

: 당신의 참고를 참조하십시오

python adder_ugly.py -v 

:

http://docs.python.org/py3k/library/unittest.html?highlight=unittest#unittest

http://docs.python.org/py3k/library/doctest.html#module-doctest

관련 문제