1
0

More than 3 years have passed since last update.

PyHamcrestを使って柔軟なunittestを書こう!

Last updated at Posted at 2019-12-25

はじめに

pythonのunittestでDict型の中にList型があって,テストをするたびに通ったり通らなかったりすることってありませんか?
私はあって悩んだのでここに書き残しておきます.
解決の糸口はこのサイト(1)からいただきました.ありがとうございます.

assertEqualで対応できないところ

ここ(2)を参考にしながら以下のようなテストを書きました.

import unittest


class VTest(unittest.TestCase):

    maxDiff = None

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_v(self):
         first_json = {
            'kind': 'voiceroid',
            'items': [
                {'name': 'aoi'},
                {'name': 'akane'},
                {'name': 'yukari'}
            ]
        }

        second_json = {
            'kind': 'voiceroid',
            'items': [
                {'name': 'yukari'},
                {'name': 'aoi'},
                {'name': 'akane'},
            ]
        }
        self.assertEqual(first_json, second_json)


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

この時itemsの順序はどうでもいいよ~中身さえあってればね・・・みたいな状況になったとします.なので,個人的にはこれはテストOKです.ですが実際に動かすと

F
======================================================================
FAIL: test_v (__main__.VTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File ".\v_test.py", line 34, in test_v
    self.assertEqual(first_json, second_json)
AssertionError: {'kin[20 chars]ems': [{'name': 'aoi'}, {'name': 'akane'}, {'name': 'yukari'}]} != {'kin[20 chars]ems': [{'name': 'yukari'}, {'name': 'aoi'}, {'name': 'akane'}]}
- {'items': [{'name': 'aoi'}, {'name': 'akane'}, {'name': 'yukari'}],
+ {'items': [{'name': 'yukari'}, {'name': 'aoi'}, {'name': 'akane'}],
   'kind': 'voiceroid'}

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)

こんな風に怒られちゃいます.
いやでも個人的には・・・・とか言ってもダメなものはダメです.というのがassertEqual関数です.
そこで,値は大事だけど順序はいらないという要望に柔軟に応えてくれるライブラリがPyHamcrest(3)です.
外部ライブラリなので

pip install PyHamcrest

でインストールしたのち先ほどのコードを以下のように書き換えます.

from hamcrest import *
import unittest


class VTest(unittest.TestCase):

    maxDiff = None

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_v(self):
        first_json = {
            'kind': 'voiceroid',
            'items': [
                {'name': 'aoi'},
                {'name': 'akane'},
                {'name': 'yukari'}
            ]
        }

        second_json = {
            'kind': 'voiceroid',
            'items': [
                {'name': 'yukari'},
                {'name': 'aoi'},
                {'name': 'akane'}
            ]
        }

        # self.assertEqual(first_json, second_json)
        assert_that(first_json, second_json)


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

これはassertEqual関数assert_that関数に変えただけです.それではテストしてみると・・・

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

きれいに通りましたね.

さいごに

要素は大事だけど順序はあんまり重要でないのに怒られて困ったーって方は一度試してみてはどうでしょうか?PyHamcrestのチュートリアル(4)はこちらですいろいろあるので他にも試してみてくださいきっとテストが柔軟になると思います!

参考

(1) Python unittest - asserting dictionary with lists
(2) 最短で試すPythonテストコード
(3) PyHamcrest
(4) PyHamcrest Tutorial

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0