在這個例子中,我們甚至不需要補充任何功能,只需創建一個帶auto-spec方法的RemovalService類,然后將該實例注入到UploadService中對方法驗證。
mock.create_autospec為類提供了一個同等功能實例。這意味著,實際上來說,在使用返回的實例進行交互的時候,如果使用了非法的方法將會引發異常。更具體地說,如果一個方法被調用時的參數數目不正確,將引發一個異常。這對于重構來說是非常重要。當一個庫發生變化的時候,中斷測試正是所期望的。如果不使用auto-spec,即使底層的實現已經破壞,我們的測試仍然會通過。
陷阱:mock.Mock和mock.MagicMock類
mock庫包含兩個重要的類mock.Mock和mock.MagicMock,大多數內部函數都是建立在這兩個類之上的。在選擇使用mock.Mock實例,mock.MagicMock實例或auto-spec方法的時候,通常傾向于選擇使用 auto-spec方法,因為它能夠對未來的變化保持測試的合理性。這是因為mock.Mock和mock.MagicMock會無視底層的API,接受所有的方法調用和參數賦值。比如下面這個用例:
1 2 3 4 |
class Target(object): def apply(value): return valuedef method(target, value): return target.apply(value) |
我們像下面這樣使用mock.Mock實例來做測試:
1 2 3 4 5 6 7 8 |
class MethodTestCase(unittest.TestCase): def test_method(self): target = mock.Mock() method(target, "value") target.apply.assert_called_with("value") |
這個邏輯看似合理,但如果我們修改Target.apply方法接受更多參數:
1 2 3 4 5 6 |
class Target(object): def apply(value, are_you_sure): if are_you_sure: return value else: return None |
重新運行你的測試,然后你會發現它仍然能夠通過。這是因為它不是針對你的API創建的。這就是為什么你總是應該使用create_autospec方法,并且在使用@patch和@patch.object裝飾方法時使用autospec參數。
真實世界的例子: 模仿一次 Facebook API 調用
在結束之際,讓我寫一個更加實用的真實世界的例子, 這在我們的介紹部分曾今提到過: 向Facebook發送一個消息. 我們會寫一個漂亮的封裝類,和一個產生回應的測試用例.
1 2 3 4 5 6 7 8 |
import facebookclass SimpleFacebook(object): def __init__(self, oauth_token): self.graph = facebook.GraphAPI(oauth_token) def post_message(self, message): """Posts a message to the Facebook wall.""" self.graph.put_object("me", "feed", message=message) |
原文轉自:http://www.diggerplus.org/archives/2704