PyCon JP 2019で発表するAPIサーバー開発で始めるCI・テスト機構の話です
© - BASE, Inc. XPythonを使ったAPIサーバー開発を始める際に整備したCIとテスト機構. . PyCon JP- @hgsgtk
View Slide
© - BASE, Inc.本⽇話すことhttps://pycon.jp/ /sessionsCIでのコード検査‧⾃動テストを取り上げます。
© - BASE, Inc.本⽇話すことCIによるコード検査‧⾃動テストの開発者⾃⾝にとっての メリットを話します。https://pycon.jp/ /sessions
© - BASE, Inc.話すこと• 学習サイクル促進のためのCI導⼊‧⾃動テストの考え⽅• Pythonでのコード検査‧⾃動テスト整備のためのキーワード• コード検査‧⾃動テストから得られるフィードバック
© - BASE, Inc.話さないこと• CIツールの⽐較• 詳細なCIの設定⽅法• テスティングフレームワークの⽐較
© - BASE, Inc.: @hgsgtkWho am I?東⼝ 和暉 ( Higashiguchi Kazuki )Back-end Engineer (Go, PHP, Python )BASE BANK, Inc. (BASE, Inc.)/ Dev Division / Tech Lead
© - BASE, Inc.お品書き.CI‧コード検査/テストに対する捉え⽅.CI導⼊‧コード検査.⾃動テスト作成‧実施.まとめ
© - BASE, Inc.CI (Continuous Integration)• 継続的インテグレーション• ビルド‧テストを頻繁に繰り返し⾏うことにより、問題を早期に発⾒、開発の効率化‧省⼒化を図る⼿法
© - BASE, Inc.CIはなぜ⼊れたい?開発の効率化‧省⼒化?• エラーを⼩さな単位で早期に修正することによる、修正コストの削減• ex. コミット単位でコンパイル‧テスト‧静的解析 …etc
© - BASE, Inc.このトークでの捉え⽅:学習サイクル促進• 業務開発での commit‧ pushから得られるフィードバックを増やす• XXX に対するフィードバック• コーディング• コード設計
© - BASE, Inc.CIで防ぎCIに学ぶ
© - BASE, Inc.コーディングに対するフィードバック• PEP ‧PEP といったコーディング‧ドキュメントスタイルを守っているか• すべてを読み込むのは⼤変‧漏れている可能性もある• コード検査で確認し、指摘結果から学ぶ
© - BASE, Inc.コード設計に対するフィードバック• テスト、特にユニットテストを書くことで、テスタビリティの声を聞く• テストがしやすい‧テストがしにくいの肌感をフィードバックとして受ける• 関⼼の分離がされた疎結合なパーツが協調するコード設計へ
© - BASE, Inc.フィードバックからすぐアクションする• テストで振る舞いを保護する• 保護されたコードの内部詳細の実装‧コーディングを改善していく
© - BASE, Inc.背景:題材事例となるアプリケーション• DB‧外部APIへ依存するAPIサービス• エンドポイントは4つほど、⽐較的⼩さいがビジネスロジックを持った• ex. ⾦額計算などを⾏う
© - BASE, Inc.様々なCIツール• 様々CI導⼊するためのツールがある• Jenkins, Travis CI, CircleCI etc• 本資料ではCircleCIを⽤いた事例を紹介
© - BASE, Inc.CircleCI jobs 例https://circleci.com/gh/hgsgtk/pycon -app/tree/master
© - BASE, Inc.CircleCIでのコード検査実施
© - BASE, Inc.Pythonコードスタイルチェック• pycodestyle• https://pypi.org/project/pycodestyle/• flake• http://flake .pycqa.org/en/latest/• Pylint• https://www.pylint.org• autopep• https://github.com/hhatto/autopep
© - BASE, Inc.コードスタイル pycodestyle• Pythonコードスタイルガイドチェックツール• PEP - Style Guide for Python Code• https://www.python.org/dev/peps/pep- /
© - BASE, Inc.pycodestyleからのフィードバック• Python Codeのスタイルガイドに準拠しているかどうかが指摘される• 「Pythonの標準的なコードが書けているか?」
© - BASE, Inc.Pythonドキュメントスタイルチェック• pydocstyle• https://pypi.org/project/pydocstyle/
© - BASE, Inc.pydocstyle• Pythonのdocstring規約への準拠を確認する静的分析ツール• PEP — Docstring Conventions • https://www.python.org/dev/peps/pep- /
© - BASE, Inc.pydocstyleからのフィードバック• “Code is read much more often thanit is written” by Guido• 「読まれるコードドキュメントが作れているか?」
© - BASE, Inc.Pythonコード型検査• mypy• http://mypy-lang.org/
© - BASE, Inc.mypy• コード上の型を静的解析するツール• PEP — Type Hints• https://www.python.org/dev/peps/pep- /
© - BASE, Inc.mypyからのフィードバック• 「型アノテーションを設定するコード‧設定に違反したコードが書かれていないか?」
© - BASE, Inc.CI導⼊‧コード検査のまとめ• CIツールを⽤いる• コーディングスタイル‧ドキュメントスタイル‧型検査を実施する• それらからコーディングに対するフィードバックをもらう
© - BASE, Inc.⾃動テスト実施の選択肢• テストコードを作成‧実⾏するためのテスティングツールを利⽤する• pytest• https://docs.pytest.org/en/latest/• unittest• nose etc
© - BASE, Inc.pytest テストコード例
© - BASE, Inc.⾃動テストでしたいこと• コード設計へのフィードバックを得る• 関⼼の分離がされた疎結合なパーツが協調するコード設計か• 既存の振る舞いを保護し、リファクタリングをスピーディにする
© - BASE, Inc.そのために考えること.外部環境からの隔離.依存関係の差し替え可能なコード設計
© - BASE, Inc.そのために考えること(1):外部環境からの隔離• テストスコープを対象アプリケーション内に留めたい• 対象外(ex. 外部APIなど)を含めた場合ネットワーク状態などに依存し不安定なテストになりうる
© - BASE, Inc.背景:アプリケーション構造(概要)外部APIDBHTTPREQUESTHTTPHandlerDatabaseAccessInside API ApplicationAPIClientDomainLogic
© - BASE, Inc.(補⾜)背景:アプリケーション詳説• HTTP Handler: aiohttp• Asynchronous HTTP Client/Serverfor asyncio and Python.• http://docs.aiohttp.org/en/stable/• Database Access: sqlalchemy• The Python SQL Toolkit and Object RelationalMapper• https://www.sqlalchemy.org/
© - BASE, Inc.テスト⽤ライブラリを活⽤する外部APIDBHTTPREQUESTHTTPHandlerDatabaseAccessInside API ApplicationAPIClientDomainLogicpytest-aiohttp• pytest plugin for aiohttp• 擬似的なリクエストを再現• https://github.com/aio-libs/pytest-aiohttp
© - BASE, Inc.テスト⽤ライブラリを活⽤する外部APIDBHTTPREQUESTHTTPHandlerDatabaseAccessInside API ApplicationAPIClientDomainLogickevin /vcrpy• 実⾏されたHTTPリクエスト/レスポンスを記録‧再⽣する• https://vcrpy.readthedocs.io/en/latest/
© - BASE, Inc.テスト⽤ライブラリを活⽤しないもの外部APIDBHTTPREQUESTHTTPHandlerDatabaseAccessInside API ApplicationAPIClientDomainLogic
© - BASE, Inc.テスト⽤ライブラリを活⽤しないもの• データベースへの問い合わせをモックするかどうか• たとえば、Goでは DATA-DOG/go-sqlmock という実⾏されるSQLが期待通りかを検証するモックを作成する⽅法がある• https://github.com/DATA-DOG/go-sqlmock
© - BASE, Inc.モックに置き換えるかどうか• ⻑所は、テストの速度‧安定度• ⼀⽅、短所は、統合した際に期待通り動作するという安⼼感• ex. SQLが本当に正しい?
© - BASE, Inc.結果的に⾏った施策外部APIDBHTTPREQUESTHTTPHandlerDatabaseAccessInside API ApplicationAPIClientDomainLogic• テスト⽤DBを作成する(本例ではコンテナ)
© - BASE, Inc.テスト⽤DBを作成する
© - BASE, Inc.テスト⽤DBを利⽤する※ スキーマ‧フィクスチャ管理については時間の都合上‧‧‧
© - BASE, Inc.「外部環境からの隔離」のフィードバック• テスト⽤ライブラリで外部環境との接点を差し替えれる• ⼀⽅で、すべてのテストケースでこれらで差し替えるようなコードの場合、疎結合なコード設計になっていない可能性を⽰唆
© - BASE, Inc.背景:アプリケーション構造(概要)外部APIDBHTTPREQUESTHTTPHandlerDatabaseAccessInside API ApplicationAPIClientDomainLogicたとえば、HTTP HandlerのテストをするのにDB‧外部APIすべてライブラリで差し替えるのは「前準備のコスト」が⾼い
© - BASE, Inc.依存関係の差し替え可能なコード設計• 依存関係をなるべく差し替え可能へ• DI(Dependency Injection: 依存関係の注⼊)可能な設計へ
© - BASE, Inc.DI可能にするconstructorからオブジェクトを受け付ける
© - BASE, Inc.DI可能にするテスト時には仮の値を返すテストダブルに置き換える※ テストダブル: テスト固有の同等物(ex. スタブ‧モック)
© - BASE, Inc.依存関係の差し替え⼿段• ⾃分でテスト⽤の代替クラスを作成• モックライブラリ利⽤• pytest-mock• https://pypi.org/project/pytest-mock/• spy, stub, mockが可能
© - BASE, Inc.「依存関係の差し替え可能なコード設計」のフィードバック• テストの前準備のコスト‧実⾏速度が、疎結合なコード設計へ⽬を向けるきっかけへ
© - BASE, Inc.おまけ 〜⾃動テストの維持のために〜• pytest-randomly で不安定なテストに気づく• https://pypi.org/project/pytest-randomly/• 実⾏順に依存するテストは、⼀般的に不安定なテストと呼ばれる、⾃動テスト維持にはデメリットになるRefs: “Pythonでの開発を効率的に進めるためのツール設定” at PyConJP by @aodag さんhttps://www.slideshare.net/aodag/python-
© - BASE, Inc.まとめ• CIを回すことで継続的なフィードバック環境を作る• コード検査からコーディングを、テストからコード設計へのフィードバックをもらう
© - BASE, Inc.まとめ• コード検査‧⾃動テストなどはある種「⾯倒だけどやったほうが良いこと」と捉えられがち• 開発者にフィードバックをくれるものと捉えて、「前向き」な捉え⽅をする⼀つのアイデアでした