2015-05-14 182 views
1

我有一個Python類,它的__init__方法引發了一個名爲WrongFileSpecified的自定義異常。但是,當我編寫單元測試時,我想從測試夾具分配實例對象的屬性。所以通常我會做的是從文件中讀取數據,然後使用實例對象。通過__init__構造對象並忽略構造函數異常

但是通過測試,我無法使用任何測試文件,所以我基本上需要硬編碼單元測試的setUp方法中的實例對象中的數據。有什麼辦法可以創建一個沒有__init__抱怨異常的實例嗎?

樣品的編號:

class A(object): 
    def __init__(self, folderPath): 
     #check folder path using os.isdir() otherwise raise exception 
     #... 
     self.folderPath = folderPath 
     #Call load record 
     self._load_records() #uses self.folderPath and raises exceptions as well 

     #Note i cannot avoid raising these exceptions, its required 

class TestA(unittest.TestCase): 
    ....... 
    obj = None 
    def setUp(self): 
     obj = A('fake folder path') 
     obj.val1 = "testparam1" 
     obj.param2 = "testparam2" 

    def test_1(self): 
..... 
+5

你爲什麼不動的邏輯從文件讀取數據到一個類的方法,所以你會打電話例如'MyClass的。from_file(whatever_file)'而不是'MyClass(whatever_file)'? – jonrsharpe

+1

請發佈您的代碼,這聽起來像它將受益於重新設計,讓它是可測試的? – dm03514

+0

不能發佈代碼抱歉不披露,但我會在幾分鐘內寫一個樣本版本 – user3413046

回答

0

這裏有兩個選項:

  1. 重構的文件加載出到類方法,它是提供一種可選的構造的Python化方法(見下文);或
  2. __init__提供一個附加參數,以在必要時抑制例外(例如def __init__(self, folderPath, suppress=False)validate=True,以使用者爲準)。

後者有點尷尬,在我看來,但這意味着你不必重構現有的代碼來創建A實例。前者看起來像:

class A(object): 

    def __init__(self, ...): 
     """Pass whatever is loaded from the file to __init__.""" 
     ... 

    @classmethod 
    def from_file(cls, folderPath): 
     """Load the data from the file, or raise an exception.""" 
     ... 

並且您將替換例如a = A(whatever)a = A.from_file(whatever)

0

有一個非常有用的模塊mock,你可以稍後檢查一下,我覺得在這種情況下它會太多。相反,你應該考慮重新設計類,像這樣的,例如:

class A(object): 

    def __init__(self, folderPath): 
     self.folderPath = folderPath 

    def _load_records(self) 
     #check folder path using os.isdir() otherwise raise exception 
     ... 
     #uses self.folderPath and raises exceptions as well 
     ... 

    @classmethod 
    def load_records(cls, folderpath): 
     obj = cls(folderpath) 
     obj._load_records() 
     return obj 

    # Usage 
    records = A.load_records('/path/to/records') 

然後,你可以這樣做:

class TestA(unittest.TestCase): 
    ....... 
    obj = None 
    def setUp(self): 
     self.obj = A('fake folder path') 
     self.obj.val1 = "testparam1" 
     self.obj.param2 = "testparam2" 

    def test_1(self): 
     self.assertRaises(self.obj._load_records, HorribleFailureError) 

此外,我強烈建議檢查出pytest,它爲測試夾具的精彩設施包括文件和文件夾的裝置。

+0

謝謝我感謝詳細的答案,但不幸的是,我無法避免在構造函數外加載記錄。不是我決定這麼做,但是有沒有解決異常的辦法? – user3413046

+0

當然。就像我建議的那樣,看看'mock'模塊或'pytest'設備。儘管對於初學者來說,兩者都可能有點複雜,所以祝你好運。你也可以使用https://docs.python.org/2/library/tempfile.html提供真實的文件輸入。 – letitbee

1

您可以使用__new__繞過__init__來創建空對象。

obj = obj_type.__new__(obj_type) 

注意obj_type是適當的type對象。這是一個小黑客,但它的作品。您有責任設置對象的成員。

編輯:這裏是一個例子。

class Foo(): 
    def __init__(self): 
     self.x = 1 
     self.y = 2 

    def say_hello(self): 
     print('Hello!') 

r = Foo.__new__(Foo) 

r.say_hello() 

print(r.x) 

控制檯輸出:

Hello! 
Traceback (most recent call last): 
    File "C:\WinPython-64bit-3.3.5.7\python- 
    3.3.5.amd64\Scripts\projects\luc_utils\dev\test\ 
unit_test_serialization.py", line 29, in <module> 
print(r.x) 
AttributeError: 'Foo' object has no attribute 'x' 
+0

對不起,我還在旅行,現在不能訪問電腦,請按照您所提到的設置實例方法,設置成員是手動完成的嗎? – user3413046

+0

你好。我認爲我的例子可能會回答你的問題。讓我知道如果它不。謝謝。 –

+0

完美謝謝:) – user3413046