5.22.2011

Python unit testing

Python: ユニットテストの実行

このページ(Dive Into Python)が分かりやすかった。
http://diveintopython3-ja.rdy.jp/unit-testing.html

Pythonでは、テスト駆動開発(TDD/Test-Driven Development)に必要なツールが標準で用意されている。

以下の手順で実行。

・unittest モジュールをインポート
・「unittest.TestCase」を継承するクラスを作成
・「test」で始まる名前のクラスメソッドを作成
・そのメソッドの中でテストしたい処理を実行 ⇒ 例外が発生せずメソッドが完了すれば、テストOKとなる
・同値性の確認:self.assertEqual(first, second)
・特定の例外が発生することの確認:self.assertRaises(excClass)
  ⇒ with ステートメントを使うと非常にスマートなコーディングができる。
・unittest.main() を実行

以上を踏まえ、将棋の駒クラスのユニットテストを実装。

・test_piece.py

#!/usr/bin/python2.7
# Copyright (c) 2011 Mog Project. All rights reserved.
from shogi.piece import Piece
from shogi.piece import PieceError
import unittest

class Test(unittest.TestCase):
  # csa, owner, type, origin, reverse, promote
  all_pieces = (
      (None, ' ', '* ', ' * ', ' * ', None),
      (' * ', ' ', '* ', ' * ', ' * ', None),
      (' XX', ' ', '* ', ' * ', ' * ', None),
      ('+FU', '+', 'FU', '+FU', '-FU', '+TO'),
      ('+KY', '+', 'KY', '+KY', '-KY', '+NY'),
      ('+KE', '+', 'KE', '+KE', '-KE', '+NK'),
      ('+GI', '+', 'GI', '+GI', '-GI', '+NG'),
      ('+KI', '+', 'KI', '+KI', '-KI', None),
      ('+KA', '+', 'KA', '+KA', '-KA', '+UM'),
      ('+HI', '+', 'HI', '+HI', '-HI', '+RY'),
      ('+OU', '+', 'OU', '+OU', '-OU', None),
      ('+TO', '+', 'TO', '+FU', '-TO', None),
      ('+NY', '+', 'NY', '+KY', '-NY', None),
      ('+NK', '+', 'NK', '+KE', '-NK', None),
      ('+NG', '+', 'NG', '+GI', '-NG', None),
      ('+UM', '+', 'UM', '+KA', '-UM', None),
      ('+RY', '+', 'RY', '+HI', '-RY', None),
      ('-FU', '-', 'FU', '-FU', '+FU', '-TO'),
      ('-KY', '-', 'KY', '-KY', '+KY', '-NY'),
      ('-KE', '-', 'KE', '-KE', '+KE', '-NK'),
      ('-GI', '-', 'GI', '-GI', '+GI', '-NG'),
      ('-KI', '-', 'KI', '-KI', '+KI', None),
      ('-KA', '-', 'KA', '-KA', '+KA', '-UM'),
      ('-HI', '-', 'HI', '-HI', '+HI', '-RY'),
      ('-OU', '-', 'OU', '-OU', '+OU', None),
      ('-TO', '-', 'TO', '-FU', '+TO', None),
      ('-NY', '-', 'NY', '-KY', '+NY', None),
      ('-NK', '-', 'NK', '-KE', '+NK', None),
      ('-NG', '-', 'NG', '-GI', '+NG', None),
      ('-UM', '-', 'UM', '-KA', '+UM', None),
      ('-RY', '-', 'RY', '-HI', '+RY', None),
      )

  def test_all(self):
    print '[All pieces]'
    for csa, owner, type_, origin, reverse, promote in self.all_pieces:
      print csa, owner, type_, origin, reverse, promote
      p = Piece() if not csa else Piece(csa)
      self.assertEqual(str(p), '%s%s' % (owner, type_))
      self.assertEqual(repr(p), "Piece('%s%s')" % (owner, type_))
      self.assertEqual(p.owner(), owner)
      self.assertEqual(p.type_(), type_)
      self.assertEqual(p.origin(), Piece(origin))
      self.assertEqual(p.reverse(), Piece(reverse))
      self.assertEqual(p.is_promotable(), promote != None)
      if promote:
        self.assertEqual(p.promote(), Piece(promote))

  def test_initialize_error(self):
    print '[Initialize errors]'
    for csa in ('', ' ', '-', 'SPAM', '=FU', '+Fu', 0):
      with self.assertRaises(PieceError) as cm:
        Piece(csa)
      print cm.exception

  def test_modify_error(self):
    print '[Modify error]'
    with self.assertRaises(TypeError) as cm:
      x = Piece('+FU')
      x.csa = '-FU'
    print cm.exception

  def test_delete_error(self):
    print '[Delete error]'
    with self.assertRaises(TypeError) as cm:
      x = Piece('+FU')
      del x.csa
    print cm.exception

  def test_promote_error(self):
    print '[Promote errors]'
    for x in (None, '+', '-'):
      for y in ('OU', 'KI', 'TO', 'NY', 'NK', 'NG', 'UM', 'RY'):
        with self.assertRaises(PieceError) as cm:
          if not x:
            Piece().promote()
          else:
            Piece(x + y).promote()
        print cm.exception
        if not x: break


if __name__ == "__main__":
  unittest.main()


・出力結果(Eclipse + Pydev で実行)

pydev debugger: warning: psyco not available for speedups (the debugger will still work correctly, but a bit slower)
pydev debugger: starting
Finding files... done.
Importing test modules ... done.

[All pieces]
None   *   *   *  None
*    *   *   *  None
XX   *   *   *  None
+FU + FU +FU -FU +TO
+KY + KY +KY -KY +NY
+KE + KE +KE -KE +NK
+GI + GI +GI -GI +NG
+KI + KI +KI -KI None
+KA + KA +KA -KA +UM
+HI + HI +HI -HI +RY
+OU + OU +OU -OU None
+TO + TO +FU -TO None
+NY + NY +KY -NY None
+NK + NK +KE -NK None
+NG + NG +GI -NG None
+UM + UM +KA -UM None
+RY + RY +HI -RY None
-FU - FU -FU +FU -TO
-KY - KY -KY +KY -NY
-KE - KE -KE +KE -NK
-GI - GI -GI +GI -NG
-KI - KI -KI +KI None
-KA - KA -KA +KA -UM
-HI - HI -HI +HI -RY
-OU - OU -OU +OU None
-TO - TO -FU +TO None
-NY - NY -KY +NY None
-NK - NK -KE +NK None
-NG - NG -GI +NG None
-UM - UM -KA +UM None
-RY - RY -HI +RY None
[Delete error]
piece object is read-only
[Initialize errors]
piece type error ('')
piece type error (' ')
piece type error ('-')
piece type error ('SPAM')
piece type error ('=FU')
piece type error ('+Fu')
piece type error (0)
[Modify error]
piece object is read-only
[Promote errors]
unpromotable piece ( * )
unpromotable piece (+OU)
unpromotable piece (+KI)
unpromotable piece (+TO)
unpromotable piece (+NY)
unpromotable piece (+NK)
unpromotable piece (+NG)
unpromotable piece (+UM)
unpromotable piece (+RY)
unpromotable piece (-OU)
unpromotable piece (-KI)
unpromotable piece (-TO)
unpromotable piece (-NY)
unpromotable piece (-NK)
unpromotable piece (-NG)
unpromotable piece (-UM)
unpromotable piece (-RY)
----------------------------------------------------------------------
Ran 5 tests in 0.058s

OK

0 件のコメント:

コメントを投稿