Source

mock_test /

Filename Size Date modified Message
minimock_test
229 B
6.4 KB
52 B

Mock 調査

外部の変化する事柄からテストを分離させることが目的

  • 外部通信
  • 現在時刻

とかとか

だいたいの有名どころ

こんなドキュメント見つけちゃって、もうヤル気なくした

http://garybernhardt.github.com/python-mock-comparison/

Mock

  • unittest と一緒に使われることを想定
  • 'action -> assertion' パターン
  • python2.4-2.7, python3 対応
  • Mock, MagicMock クラス
  • patch() デコレータ

Mocker

  • 'record -> replay' パターン

  • unittest.TestCase の拡張クラス提供

    • assertIs
    • assertIn など
  • python2.4-2.6 対応

  • こんな感じ:

    >>> mocker = Mocker()
    >>> # モックオブジェクト生成
    >>> obj = mocker.mock()
    
    >>> # 期待される hello() メソッド呼び出しを記録
    >>> obj.hello()
    >>> # hello() は呼び出されると 'Hi!' を返すべき
    >>> mocker.result('Hi!')
    
    >>> # mocker をリプレイモードに
    >>> mocker.replay()
    
    >>> # 実際に期待される結果を返すか確認
    >>> obj.hello()
    'Hi!'
    
    >>> # 想定していないメソッド bye() を呼び出すと例外を吐く
    >>> obj.bye()
    Traceback (most recent call last):
      ...
    mocker.MatchError: [Mocker] Unexpected expression: obj.bye
    
    >>> # 最後に、これらの変更を元に戻す
    >>> mocker.restore()
    >>> # そして定義した全ての例外を発生させたか確認
    >>> mocker.verify()
    
  • with mocker を使えばもっとエレガントに:

    >>> obj = mocker.mock()
    
    >>> obj.hello()
    >>> mocker.result('Hi!')
    
    >>> # mocker.replay() -> yield -> mocker.restore() -> mocker.verify() してくれる
    >>> with mocker:
    ...     obj.hello()
    'Hi!'
    
  • MockerTestCase を提供:

    >>> class SampleTest(MockerTestCase):
    ...     # 各テスト完了時に verify, restore してくれる
    ...     def test_hello(self):
    ...         obj = self.mocker.mock()
    ...         obj.hello()
    ...         self.mocker.result('Hi!')
    ...         self.mocker.replay()
    ...         self.assertEquals(obj.hello(), 'Hi!')
    
  • その他色々なモックの振舞い:

    >>> obj = mocker.mock()
    >>> len(obj.attr.method('param'))
    >>> mocker.result(3)
    
    >>> mocker.replay()
    
    >>> method = obj.attr.method
    >>> result = method('param')
    >>> len(result)
    3
    
  • モックの振舞い定義方法は2つの方法がある

    • mocker インスタンスのメソッド呼び出し:

      >>> obj1 = mocker.mock()
      >>> obj1.hello()
      >>> mocker.result('Hi')
      
    • expect() ヘルパー関数:

      >>> obj2 = mocker.mock()
      >>> expect(obj2.hello()).result('Hi!')
      
  • モックの反応定義API

    • result(value)
    • generate(seqence)
    • throw(exception)
    • call(func, with_object=False)
    • countt(min[, max])
    • passthrough([result_callback])
  • 引数のマッチング

    例:

    >>> obj = mocker.mock()
    
    >>> # これはまあ普通
    >>> obj.hello('Joe', 'morning')
    >>> mocker.result('Good morning, Joe!')
    
    
    >>> obj.hello('Jeff', ANY)
    >>> mocker.call(lambda name, when: 'Good %s, Jeff' % when)
    
    >>> # 第2引数が 'Joe' である
    >>> obj.hello(ANY, 'Joe', ARGS, KWARGS)
    
    • ANY
    • ARGS
    • KWARGS
    • IS(object)
    • IN(object)
    • CONTAINS(object)
    • MATCH(func)
    • 今のとこ、クラスメソッドには使えないっす
  • 振舞いの登録順呼び出しの強制もできる

    • mocker.order(): with 句にも使えるよ
    • mocker.unorder(): デフォルトは順不同
  • Mocker 特有の機能

    • 既存のオブジェクトへのプロキシ:

      >>> # greeting インスタンスにプロキシ
      >>> obj = mocker.proxy(greeting)
      
      >>> # time() を上書き(事前に上書き対象をimportしておく必要がある)
      >>> from time import time
      >>> obj = mocker.replace('time.time')
      
    • 実際のクラス/インスタンスへのパッチ:

      >>> # greeting インスタンスにパッチ
      >>> obj = mocker.patch(greeting)
      
      >>> obj.hello('Jeff')
      <mocker.Mock object at 0x100761850>
      >>> mocker.result('Hello Jeff!')
      
      >>> mocker.replay()
      
      >>> greeting.hello('Jeff')
      'Hello Jeff!'
      >>> greeting.hello('Joe')
      'Hi Joe!'
      
      >>> type(greeting)
      <class '__main__.Greeting'>
      
      >>> # restore で復帰
      >>> mocker.restore()
      >>> greeting.hello('Jeff')
      'Hi Jeff!'
      
  • 型のシミュレーション

    プロキシでも mock オブジェクトでも可能:

    >>> obj = mocker.mock(Greeting)
    
    >>> mocker.replay()
    
    >>> obj.__class__
    <class '__main__.Greeting'>
    
    >>> isinstance(obj, Greeting)
    True
    
    >>> type(obj)
    <class 'mocker.Mock'>
    
  • unittest.TestCase の拡張クラス提供

MiniMock

  • Ian Bicking

  • おやかた推薦

  • シンプルなモックオブジェクトライブラリ

  • 特に doctest 向け

  • doctest で以下を確認できる

    • 指定のオブジェクトにおいて予期していないメソッドが呼ばれていないこと
    • モックオブジェクトに渡された引数
    • 返り値
  • こんな感じ:

    >>> smtplib.SMTP = Mock('smtplib.SMTP')
    >>> smtplib.SMTP.mock_returns = Mock('smtp_connection')
    
    >>> send_email('ae35@beproud.jp', 'bucho@beproud.jp',
    ...            'Let me show your...', 'xxx')
    Called smtplib.SMTP('localhost')
    Called smtp_connection.sendmail(
        'ae35@beproud.jp',
        ['bucho@beproud.jp'],
        'To: bucho@beproud.jp\nFrom: ae35@beproud.jp\nSubject: Let me show your...\n\nxxx')
    Called smtp_connection.quit()
    
  • unittest だと返り値しか確認できない

  • モックの作成例その1:

    >>> from minimock import Mock
    >>> dummy_module = Mock('mylibrary')
    >>> dummy_module.CONSTANT = 1
    
  • モックの作成例その2:

    >>> from minimock import mock
    >>> import os.path  # 必要なモジュールを先にインポートしておく
    >>> mock('os.path.isfile', returns=True)
    
  • mock() を使用した場合の復帰:

    >>> minimock.restore()
    
  • Mock を使うなら、必要に応じて自前で復帰する必要あり