2016-06-10 93 views
-1

我正在編寫讀取文件並根據該文件內容創建字典的代碼。代碼非常簡單,但我想測試邊緣情況。爲什麼我的斷言在讀取NamedTemporaryFile時失敗?

這裏是我的嘗試:

from tempfile import NamedTemporaryFile 
from nose.tools import * 

def read_file(filename): 
    with open(filename) as f: 
     my_dict = { dict(line.strip().split(',')) for line in f } 
    return my_dict 

def test_read_file(): 
    file_contents = b"""Hello,World""" 
    with NamedTemporaryFile() as fp: 
     fp.write(file_contents) 
     my_dict = read_file(fp.name) 
    print(my_dict) 
    assert my_dict == { "Hello" : "World" } 

不幸的是,因爲my_dict是一個空的字典此斷言失敗。

我的理解是,一旦NamedTemporaryFile關閉時,它被摧毀,所以我不希望它被破壞read_filemy_dict填充直接後直到fp正在打開兩次:一次寫入,一次讀取 - 這是麻煩製造者嗎?

這是測試讀取文件的函數的正確方法嗎?如果是這樣,爲什麼我的斷言失敗了?如果不是,寫這個測試的更好的機制是什麼?

+0

您可能需要調用'fp.flush()'以確保數據在您嘗試讀取之前實際寫入文件。 – chepner

+0

@chepner呃,就是這樣。如果您想添加答案,我會接受它。不過,這幾乎肯定是一個騙局。 – erip

回答

2

您需要刷新寫入以確保數據在讀取之前被寫入。

def test_read_file(): 
    file_contents = b"""Hello,World""" 
    with NamedTemporaryFile() as fp: 
     fp.write(file_contents) 
     fp.flush() 
     my_dict = read_file(fp.name) 
    print(my_dict) 
    assert my_dict == { "Hello" : "World" } 
+0

接受這個是因爲它回答_why_的問題,但是提出了另一個答案,因爲這是一個更好的方法。 – erip

1

除了使用真實文件外,還可以使用類似於內存文件的對象。這需要嘲笑open,或者更改您的API以獲取文件類對象而不是文件名。

import unittest.mock 
import io 

def test_read_file(): 
    file_contents = io.BytesIO(b"""Hello,World""") 
    m = unittest.mock.mock_open(read_data=file_contents) 
    with unittest.mock.patch('__main__.open', m): 
     my_dict = read_file("fake.txt") 
    print(my_dict) 
    assert my_dict == { "Hello" : "World" } 
+0

'unittest'包含一些非常瘋狂的東西!不過,我喜歡內存中的對象。 – erip