簡體   English   中英

如何為Python單元測試提供stdin,文件和環境變量輸入?

[英]How to supply stdin, files and environment variable inputs to Python unit tests?

如何在出現以下條件的情況下編寫測試:

  1. 測試用戶輸入。
  2. 測試從文件讀取的輸入。
  3. 測試從環境變量讀取的輸入。

如果有人能告訴我如何處理上述場景,那就太好了; 如果你能指出我可以閱讀的一些文檔/文章/博客文章,它仍然很棒。

您描述的所有三種情況都是您需要特別注意的地方,以確保您在設計中使用松耦合。

真的需要對Python的raw_input方法進行單元測試嗎? open方法? os.environ.get 沒有。

您需要設置您的設計,以便替換其他方式來檢索該輸入。 然后,在單元測試期間,您將拋出某種實際上不調用raw_inputopen的存根。

例如,您的普通代碼可能是這樣的:

import os
def say_hello(input_func):
    name = input_func()
    return "Hello " + name

def prompt_for_name():
    return raw_input("What is your name? ")

print say_hello(prompt_for_name)
# Normally would pass in methods, but lambdas can be used for brevity
print say_hello(lambda: open("a.txt").readline())
print say_hello(lambda: os.environ.get("USER"))

會話看起來像:

What is your name? somebody
Hello somebody
Hello [some text]

Hello mark

然后你的測試將是:

def test_say_hello():
    output = say_hello(lambda: "test")
    assert(output == "Hello test")

請記住,您不必測試語言的IO設施(除非您是設計語言的人,完全是另一種情況)。

如果你使用raw_input(或任何其他特定的輸入源),我是模擬庫的主要支持者。 鑒於Mark Rushakoff在他的例子中使用的代碼:

def say_hello():
    name = raw_input("What is your name? ")
    return "Hello " + name

您的測試代碼可以使用mock:

import mock

def test_say_hello():
     with mock.patch('__builtin__.raw_input', return_value='dbw'):
         assert say_hello() == 'Hello dbw'

     with mock.patch('__builtin__.raw_input', side_effect=['dbw', 'uki']):
         assert say_hello() == 'Hello dbw'
         assert say_hello() == 'Hello uki'

這些斷言會通過。 請注意,side_effect按順序返回列表的元素。 它可以做得更多! 我建議查看文檔。

如果您可以在不使用外部流程的情況下離開,請執行此操作。

但是,有些情況下這很復雜,並且您確實想要使用進程,例如,您想要測試C可執行文件的命令行界面。

用戶輸入

使用subprocess.Popen如下所示:

process = subprocess.Popen(
    command,
    shell  = False,
    stdin  = subprocess.PIPE,
    stdout = subprocess.PIPE,
    stderr = subprocess.PIPE,
    universal_newlines = True
)
stdout, stderr = process.communicate("the user input\nline 2")
exit_status = process.wait()

從使用者輸入和從管道獲取輸入以使用raw_inputsys.stdin.read()等方法完成輸入之間沒有區別。

  • 創建一個臨時目錄,並在測試setUp方法中創建要讀取的文件:

     tdir = tempfile.mkdtemp( prefix = 'filetest_', ) fpath = os.path.join(tdir,'filename') fp = open(fpath, 'w') fp.write("contents") fp.close() 
  • 在測試中讀取文件。

  • 之后移除臨時目錄。

     shutil.rmtree(tdir) 
  • 讀取文件非常復雜,大多數程序可以從文件或STDIN中讀取(例如,使用fileinput )。 因此,如果您要測試的是輸入某個內容時發生的情況,並且您的程序接受STDIN,則只需使用Popen來測試該程序。

環境變量

  • 使用os.environ["THE_VAR"] = "the_val"設置環境變量
  • 使用del os.environ["THE_VAR"]取消設置
  • os.environ = {'a':'b'}不起作用
  • 然后調用subprocess.Popen 環境繼承自調用進程。

模板代碼

我的github上有一個模塊,用於測試STDOUTSTDERR以及給定STDIN ,命令行參數和環境的退出狀態。 另外,在“tests”目錄下檢查該模塊的測試。 那里必須有更多更好的模塊,所以我的目的只是為了學習目的。

使用pytest

import os


def test_user_input(monkeypatch):
    inputs = [10, 'y']
    input_generator = (i for i in inputs)
    monkeypatch.setattr('__builtin__.raw_input', lambda prompt: next(input_generator))
    assert raw_input('how many?') == 10
    assert raw_input('you sure?') == 'y'


def test_file_input(tmpdir):
    fixture = tmpdir.join('fixture.txt')
    fixture.write(os.linesep.join(['1', '2', '3']))
    fixture_path = str(fixture.realpath())
    with open(fixture_path) as f:
        assert f.readline() == '1' + os.linesep


def test_environment_input(monkeypatch):
    monkeypatch.setenv('STAGING', 1)
    assert os.environ['STAGING'] == '1'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM