Mock and patch

2,172 views

Published on

Python mock ライブラリの紹介

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,172
On SlideShare
0
From Embeds
0
Number of Embeds
62
Actions
Shares
0
Downloads
10
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Mock and patch

  1. 1. Mock  と  patch ふるかわとおる
  2. 2. お前、誰よ? •  ふるかわとおる   –  @torufurukawa   –  bucho  と呼ばれています  •  株式会社バスキュール   –  生放送テレビ番組と連動するサービス   –  エンジニア足りません  
  3. 3. ユニットテスト def  test():      result  =  foo(wozozo)      assert  result  ==  unko  
  4. 4. 依存先… def  foo(name):      f  =  urlopen(http://%s.com/  %  name)      raw  =  f.read()      d  =  json.loads(raw)   不確定    return  d[data] 確定的な   結果に依存
  5. 5. ユニットテストしにくい例 •  戻り値が不確定   –  乱数   –  時刻  •  セットアップがだるい   –  データベース   –  Web  API  
  6. 6. テスト対象の外側を入出力として扱う ここも入出力 よびだし HTTP  req def  foo(name):      raw  =  urlopen(http://…)      d  =  json.loads(raw)      return  d[data] 戻り値 HTTP  resp
  7. 7. そこで  mock  モジュール ですよ •  Python  3.2  以前 PyPI   –  easy_install,  pip,  etc.  •  Python  3.3  標準ライブラリ   –  uniDest.mock  
  8. 8. 1:  依存先オブジェクトを入れ替える テスト対象 urlopen テスト対象 mock
  9. 9. with  patch(...)  で入れ替える from  unittest.mock  import  patch  def  test():      with  patch(urllib.request.urlopen)      as  m:          result  =  foo(wozozo)  
  10. 10. Mock  オブジェクトと入れ替え >>>  with  patch(urllib.request.urlopen)          as  m:  ...      from  urllib.request  import  urlopen  ...      urlopen  is  m  ...    True
  11. 11. Mock  オブジェクトはアクセスし放題 >>>  m  <MagicMock  name=urlopen  id=1>  >>>  m.read()  <MagicMock  name=urlopen.read()  id=2>  >>>  m.hoge  <MagicMock  name=urlopen.hoge  id=3>  
  12. 12. @patch  で入れ替える @patch(urllib.request.urlopen)  def  test(m):      result  =  foo(wozozo)  
  13. 13. setUp  と tearDown  で  patch class  MyTest(TestCase):      def  setUp(self):          self.patcher  =  patch(...)          self.m  =  patcher.start()        def  tearDown(self):          self.patcher.stop()
  14. 14. 2:  依存先の呼び出し履歴を確認 テスト テスト対象 mock
  15. 15. call_count  で呼び出し回数を確認 @patch(urllib.request.urlopen)  def  test(m):      result  =  foo(wozozo)      assert  m.call_count  ==  1  
  16. 16. call_args  で引数を確認 @patch(urllib.request.urlopen)  def  test(m):      result  =  foo(wozozo)      assert  m.call_count  ==  1      assert  (m.call_args  ==                      ((http://...,),  {}))  
  17. 17. *args  と  **kw  が返ってくる m(a,  b,  x=1)  ↓  m.call_args  ==  ((a,  b),  {x:  1})
  18. 18. 3:  依存先の挙動を定義する テスト テスト対象 mock
  19. 19. return_value  で戻り値定義 >>>  m.return_value  =  999  >>>  m()  999  
  20. 20. urlopen().read() def  foo(name):      f  =  urlopen(http://%s.com/  %  name)      raw  =  f.read()      d  =  json.loads(raw)      return  d[data]
  21. 21. return_value  で戻り値定義 >>>  m.return_value.meth.return_value  =  1  >>>  m().meth()  1  
  22. 22. @patch(urllib.request.urlopen)  def  test_foo(m):      m.return_value.read.return_value  =  …      result  =  foo(wozozo)      assert  m.call_count  ==  1      assert  (m.call_args  ==                      ((http://…,),  {}))      assert  result  ==  …  
  23. 23. 複雑な戻り値は side_effect >>>  def  f(x,  y):    ...      return  x  +  y  ...    >>>  m.side_effect  =  f  >>>  m(1,  2)  3
  24. 24. side_effect  に例外を指定 >>>  m.side_effect  =  TypeError  >>>  m()  Traceback  (most  recent  call  last):  ...  TypeError
  25. 25. mock  でユニットテストしやすくなる テスト テスト対象 mock
  26. 26. より詳しい話 •  公式ドキュメント  •  voluntas  「requests  と  mock  を使ってみる」   hDp://voluntas.hatenablog.com/entry/20111124/1322069748  •  ぁっぉ 「mock  はこう使え」   hDp://d.hatena.ne.jp/atsuoishimoto/20120310/1331311730  

×