2017-01-23 1 views
3

하나의 입력 (텍스트 파일)을 허용하는 Python 스크립트가 있습니다 : ./myprog.py file.txt. 스크립트는 주어진 입력을 기반으로 문자열을 출력합니다.테스트 스크립트 출력

프로그램을 테스트하고 싶은 테스트 파일 세트가 있습니다. 각 파일의 예상 출력을 알고 내 스크립트가 각 파일에 대해 올바른 출력을 생성하는지 확인하려고합니다.

이 유형의 테스트를 수행하기 위해 일반적으로 받아 들여지는 방법은 무엇입니까?

나는 테스트 프레임 워크로 파이썬의 unittest 모듈을 사용하여 생각하고 stdoutstderr을 캡처, subprocess.check_output(stderr=subprocess.STDOUT)를 통해 내 스크립트를 실행 한 다음 unittestassertEqual 실제 예상 문자열을 비교하고 있었다. 나는 더 좋은 해결책을 놓치고 있지 않다는 것을 확인하고 싶다.

+0

단위 테스트는 일반적으로 개별 함수 나 클래스에서 수행됩니다 (일반적으로 파일에 출력을 쓰거나 하위 프로세스로 실행하는 것은 포함하지 않습니다). 나는 다른 것을 추천 할 수는 없지만 튜토리얼을 테스트하는 파이썬 단위를 살펴보아야한다. 아마도이 질문을 주제와 관련이 없을 것이다. – byxor

+0

하드 드라이브의 내용이 바뀌기 때문에 기술적으로 단위 테스트가 아니지만 어쨌든 제대로 수행 할 수 있습니다. 입력과 출력을 위해 파일과 같은 객체를 사용하는 함수 내에서 기능을 이동하여 코드를 리팩토링하십시오. 정규 코드는 열린 파일 핸들과'sys.stdout'에서 전달됩니다. 하지만 단위 테스트 코드는 StringIO 버퍼를 사용합니다. 터미널에 연결된 파이프 대신 stringio에 쓰는 경우에는 차이점이 있으므로 항상 최선의 방법은 아닙니다. 당신은 결정해야 할 것입니다. – tdelaney

+0

당신은 항상'./myprog.py file.txt> result.txt'를 실행하고 나중에 파일을 비교하기 위해 도구를 사용할 수 있습니다 - 즉. 'diff result.txt expected.txt' -하지만 모든 것을 bash/batch 스크립트에 넣었을지라도 test만큼 유용하지는 않습니다. – furas

답변

2

여기에는 두 가지 문제가 있습니다. 함수 라이브러리에서와 대조적으로 프로그램을 테스트하고 함수에서 반환 된 값과 반대로 인쇄되는 것을 테스트합니다. 이 두 가지 방법 모두 테스트가 더 어려워 지므로 가능한 한 이러한 문제를 해결하는 것이 가장 좋습니다.

일반적인 기술은 함수 라이브러리를 만든 다음 프로그램을 그 주위의 얇은 래퍼로 만드는 것입니다. 이 함수는 결과를 반환하고 프로그램 만 인쇄를 수행합니다. 즉, 대부분의 코드에서 일반 단위 테스트 기술을 사용할 수 있습니다.

라이브러리와 프로그램 모두 하나의 파일을 가질 수 있습니다. 간단한 예제는 hello.py입니다.

def hello(greeting, place): 
    return greeting + ", " + place + "!" 

def main(): 
    print(hello("Hello", "World")) 

if __name__ == '__main__': 
    main() 

마지막 비트는 파일이 프로그램으로 실행되었거나 라이브러리로 가져온 것인지 여부를 알 수있는 방법입니다. import hello으로 개별 기능에 액세스 할 수 있으며 파일을 프로그램으로 실행할 수도 있습니다. See this answer for more information.

그러면 보통 단위 테스트를 작성할 수 있습니다. 여기

import hello 
import unittest 
import sys 
from StringIO import StringIO 
import subprocess 

class TestHello(unittest.TestCase): 
    def test_hello(self): 
     self.assertEqual(
      hello.hello("foo", "bar"), 
      "foo, bar!" 
     ) 

    def test_main(self): 
     saved_stdout = sys.stdout 
     try: 
      out = StringIO() 
      sys.stdout = out 
      hello.main() 
      output = out.getvalue() 
      self.assertEqual(output, "Hello, World!\n") 
     finally: 
      sys.stdout = saved_stdout 

    def test_as_program(self): 
     self.assertEqual(
      subprocess.check_output(["python", "hello.py"]), 
      "Hello, World!\n" 
     ) 

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

test_hello 함수로서 직접 단위 테스트 hello이고; 더 복잡한 프로그램에서는 테스트 할 수있는 더 많은 기능이 있습니다. 또한 우리는 단위 테스트 maintest_main을 사용하여 StringIO을 사용하여 출력을 캡처합니다. 마지막으로 프로그램이 test_as_program과 함께 프로그램으로 실행되는지 확인합니다.

중요한 것은 데이터를 반환하는 함수만큼 많은 기능을 테스트하고 인쇄 및 형식이 지정된 문자열로 가능한 한 테스트하지 않는 것입니다. 프로그램 자체를 실행하는 것은 거의 없습니다. 우리가 실제로 프로그램을 테스트하는 동안 우리가해야 할 일은 main을 호출하는지 확인하는 것입니다.

+0

위대한 설명. 나는 모듈을'example.py'라고 이름 지어야한다고 생각한다.'import example'으로 가져 오기. –

+0

@KshitijSaraogi 그냥 감시하고있다. 내가 코드 작업을하면서 테스트를 다시 복사하지 않은 채로 'example.py'에서'hello.py'로 이름을 변경했습니다. – Schwern

+0

알아두면 좋을 것 같습니다. 귀하의 예를 통해 단위 테스트에 관한 새로운 것들을 배웠습니다. –