2024.12.24
ビジネスが急速に変化する現代は「OODAサイクル」と親和性が高い 流通卸売業界を取り巻く5つの課題と打開策
リンクをコピー
記事をブックマーク
Atsushi Odagiri氏(以下、Odagiri):では次にpytestです。pytestもけっこう有名になってきたツールです。flake8とかmypyは静的チェックのツールなので、あいつらは実行させない、つまりコードの内容として「何か危ないぞ」とか「型違うよ」というのをチェックしてくれるツールです。pytestは結局のところユニットテストツールなので、テストで実際にコードを動かしてエラーが出るかというのをやりますが、もちろんみなさんユニットテストはやっていらっしゃいますよね。挙手。
(会場挙手)
はい。pytestを使っている人。
(会場挙手)
両方まだ混ざっている。そんなもんですよね。まずpytestはどういうところがツールとして優秀かというと、エラーが起こった時に、そのエラーの周辺の変数の内容まで表示してくれるという詳細なテストレポートがあります。詳細すぎるので、たくさんエラーが出るとがんばってスクロールしないといけなくなっちゃうんですが。
あとユニットテストとの違いでいえば、アドオンがあること。そしてfixtureの仕組みです。unittestでは、用意をするsetUpと片付けをするtearDownという2つのメソッドがバラけています。pytestではコンテキストマネージャの仕組みでfixtureをするので、yieldを挟むんです。準備してyieldして、そうするとテストが終わったあとにまたこのyieldのところに戻ってくるので、ここで後片付けをする。準備と後片付けを一緒にしたfixtureというのをちゃんと書けるんです。
たまに「setUpで呼ぶけど、こいつはtearDownで呼ぶ必要はないのか?」みたいなやつとかありますよね。そういうのが2つセットになってfixtureとして使えるというのがpytestのfixtureのいいところです。
あとは、始めようとするとTestCaseクラスを継承してテストメソッドの中でassert〜というメソッドを使ってチェックをするというのがunittestなんですけど、そこもういいよねと。test〜という関数だったらもうテストだし、その中でassertすれば詳細なテストレポートの中で変数の中身がわかるので、いちいちassert〜というのをいろいろ使い分けなくてもいいでしょうと。これが、pytest側のいいところだという話です。
unittestはunittestで良いところはあるのですが、今日はpytestの話なので、pytestだけお話します。
Pytestのインストールは、「pip install pytest」です。
昔はpyというライブラリの中に入っているtestというライブラリだったんですけど、みんなpytestしか使わないので分離されているわけです。pytestはアドオンが使えます。どんなアドオンがあるかというと、まずpytest-cov、coverage収集。ユニットテストしたらみなさんcoverageは取りますよね。取っていないユニットテストを実行している人?
(挙手なし)
さすがにいないね。あとは、アドオンですとpytest-djangoがありまして、いろいろできるやつです。pytest-mockは、ユニットテストのモックが中にあります。fixtureとしてパッチをしたものをちゃんときれいにしてくれるとか、結局一度も呼ばれていないモックについて警告してくれたりするので、使うといいと思います。
あとpytest-freezegunは時間関係です。mock datetimeするためのものですけど、これについてのpytest fixtureで使うことができます。いろんなアドオンがあるので調べてみるといいでしょう。どうせそのうち手作りすることになりますがね(笑)。
今日おすすめしたいpytestのアドオンは、pytest-randomlyです。これが何をするかというと、random seedを変更するのがまず1つ。そしてもう1つ、一番重要なのが、テスト順序をシャッフルするということです。
さあ、なぜテスト順序をシャッフルする必要があるのでしょうか? 例えばテスト対象で、このように固定のFILENAMEという定数の中に、何か受け取った内容をJSONで書き込むやつとJSONを読み込むやつがあります。すごいアホなことをやっているんですけど、そこは目を瞑ってください。
ではこれのテストを書きましょう。テストを書いちゃいました。まずtest_saveのほうはsaveメソッドを呼んで実際そのファイルの中身が正しいかを見るものですね。そしてtest_loadのほうですが、loadを呼んだresultの中身が書き込まれているというアホなことをやっていますが……。
これは非常に危険なテストと言いますか、「何をやっているの?」というテストなんですが、それでもユニットテストをやり始めるとこんなコードもたくさん出てきます。
まず何が問題かというと、test_loadはtest_saveの実行後じゃないと動かないんです。いきなり呼んでも動かないんですね。でもこのテストを実行すると、test_saveを呼んでtest_loadを実行するという、この順番で呼ばれてしまうので、うまくいってしまうわけです。
でも実際にはtest_saveを単独実行すると落ちてしまう。だけど、CI上ってわざわざ単独実行なんてしないので、全部実行するわけです。そうすると落ちないんですね。ということは、「じゃあこれはいつも全部テストを実行しないといけないのか?」という話になってしまう。対策として、テスト実行順序をシャッフルすることによって、順序依存のテストを発見することができる。
さっきのテストを書いたやつです。pytest-randomlyが入っていない状態で「pytest .\test_loader.py」とやって、普通に実行すると、test_save→test_loadという順番で実行させるのでうまくいってしまう。
ではここでテストを指定します。pytestがテストを1個実行するための書き方はこうなります。コロンでつないで関数を書いてください。これでちゃんとテストを実行できます。test_loaderだけ実行しようと思ったら、「pytest .\test_loader.py::test_load」となります。
ただ、今これを実行してみると実際にうまく動いてしまいます。さっきテストを実行したので、ちゃんとファイルが存在するので動いてしまうんですね。「なんで俺がfixtureの代わりをしなきゃいけないんだ」という憤りとともに、ちゃんと消してからやってみてください。そうするとエラーになるわけですね。
pytest-randomlyを入れましょう。「$ pip install pytest-randomly」とすると、pytestを実行したら自動でrandomlyがかかります。
ここでシャッフルされるのでたまにうまくいくわけですね。今回の場合2つテスト関数があるので、2分の1の確率でうまくいく。だから3回か4回ぐらいやって、だいたいうまくいけば「とりあえずいいんじゃないかな?」という感じなので、テスト順がシャッフルされるのを複数回実行して、ちゃんとうまくいったりうまくいかなかったりというのを確認しましょう。
次はtoxです。先ほどのpytestはテストランナーでしたが、toxは何かというと、テスト用の環境をいい感じで作ってくれるツールです。toxを使うとテスト用にvirtualenvを作ってその中でテストをするということができます。
あとその中でどういうテストを実行するかも設定で書いておけるので、これをつかってまずvirtualenvを切っていくので、それぞれバージョンの違うPythonのテストをするというのがまず簡単にできるようになります。プロダクションコードではそんなに使うことはないとは思いますが、ライブラリ作成者はだいたいtoxを使って、サポート対象のPythonバージョンを明確にするということをします。
あと、CI上でもtoxを一発呼ぶだけと設定しておくと、CI上でやっているテストをローカルでもすぐにtox一発で実行できます。CI上でしかできない複雑な手順を踏んだテストみたいなやつで落ちて、「ローカルで再現しねぇ」みたいなことになると「もう! あー!」となるわけですよ。そういうことがないようにtoxを使ってこのテストフローをきれいにしておくとまた効率アップできます。
toxをインストールする方法は「pip install tox」です。このへんのツールでpip installがうまくいかないようなツールはほとんどありませんので、安心してみなさん使ってくださいね。
tox.iniでどういうことを書くかというと、toxセクションでテストしたいバージョンを書いておきます。ここでpy36と37と書いてあるので、Python3.6と3.7に対するテストを、それぞれのバージョンのvirtual envを作って、その中でpytestをインストールしてあげて、pytestコマンドを実行すると。
設定ファイルがあって、ここでtoxと打ってあげると、3.6用のvirtual envを作って、その中にpytestを入れて、あと……あっ、skipsdistと書くの忘れた……。まあ、いいや(笑)。あと今開発中のパッケージもそこにインストールして、pytestコマンドを実行するというのを、Python3.6と3.7両方に対して実行してくれます。これが、手元でもtoxと打てばいいし、CI上でもtox一発でこのテストを実行することができる。
「手元に3.6ないので……」というときは、-eオプションを使ってenvを指定する。Python3.7だけ実行したければ、tox -e py37とやれば、その環境だけの実行になります。
以上、こういった効率化をするためのツールがありますが、こういったツールはまずCIで実行しないとみんなちゃんと守らないので、CIで実行します。これはレビュー前の最後の水際なので、ここでは必ず全部通しましょう。
でもCIに言われてからまた直すというと、「commitしてpushして何か実行されるのを待って……」みたいな感じで。最近CIもタスクが流れてくるのが遅いですから、それを待って「あっ、通った」とやるのは遅いです。
なのでもう一歩手前でいきましょう。そうすると、pre-commitです。commitフックもしくはpushのフックで走らせるというのがあります。
ただし、そこでもけっこうだるいです。そしたら、まずcommitする前にコマンドラインで手動実行しましょう。でも手動実行はそのうち忘れます。なので、エディタ上で自動で実行してくれて、編集したら即見えるというような感じにしましょう。
これでエディタからツールを使えるようにする。どういうときにするかというと、編集や保存と同時に警告したりフォーマッティングしてもらうようにしておけば、もう忘れないし、その場で直せる。「このcという変数使ってなくない?」ってピッと出てくれば「あっ!」と気づいてすぐ直せますよね。
あと、自分で実行して、たまに忘れてCIで落ちてがっかりというのはありますね。しかもCIけっこう遅いのに。しかもSlackでぴょーんと「落ちたよ」って感じで飛んできて、「あー」ってみんなの前で赤っ恥かくみたいな感じになるので。「お前、flake8落ちたぜ?」みたいな。そういうことがなくなります。エディタにツールを設定しましょう。
みなさんが使っているエディタはたぶんVS Code、emacs、Vim……。PyCharmはエディタかどうかわからないけど、そのぐらいかな? ほかのエディタを使っている人は信念があってやっていると思うので、がんばってちゃんと設定してあげてください。
エディタでどういう設定をしておくのが良いかというと、まず編集中にflake8やmypyの警告がバンバン出て直せるようにする。あと、保存したらすぐblackでフォーマットされるようにする。あとはテスト実行をエディタの中でやるとエラーメッセージが出ると思うんですけど、そこからすぐにそのエラーの箇所に飛べる機能も設定しておくとよいです。
あと、テストでカバーされた行がマーカーで表示されるというのまでいけるとすごくいいです。「あ、ここテスト通ってない」というのがすぐわかります。
VS codeでそれをやろうとすると、linting.flake8.enabled、mypy.enabled。……pylintはだいたいお役御免なのでenabled false、インストールしたらすぐにやる設定です。python.format.provider = “black”にして、あとformatOnSaveというのをやると、保存時にフォーマットが上がります。
次にemacsの場合は、静的チェックのフレームワークでflycheckとかflymakeがあります。そこを通して「flake8を使う」というのを入れます。flycheck-mypyとかもありますし、今後LSPのほうに寄っていくと思いますので、そこらへんはみなさんで調べてください。「emacsのLSP、まだちょっとなぁ……」とも思うので、まだ伝統的なsaveフックを使った設定方法がいいと思います。
Vim。使ってないのでわかりませんが、たぶん何かあるでしょう。
PyCharm。使ってないからわかりませんが、だいたいできるでしょう。
というわけで、今日はいろんなツールを説明しました。覚えて帰ってほしいことは、退屈なことは機械がやってくれますので、みなさん機械にガンガンチェックさせましょう。レビュアーの時間を奪わないために、機械を使いましょう。
レビュアーももっと突っ込んだレビューをしたいのに、その前段階のことがあると心がざわついて少し攻撃的になってしまうなんてこともあるわけです。flake8をチェックすればわかるようなことがレビュアーの目の前に来たら、ちょっと怒りたくもなるわけです。
そう言われたほうも直すのがちょっと嫌になって、お互いの精神衛生上良くないですから、事前に機械にチェックさせて、指摘されたところをそのまま直すということをやりましょう。
あとは、自分でやってみてほしいこととして、まだプロジェクトにこういったツールを導入していない場合は、「プロジェクトにこういう効果があるんですよ!」と導入してみましょう。CIを回しているプロジェクトであればCIに入れてみましょう。
というわけで、これでビギナーセッションの、開発を効率化するツール設定のお話を終わります。
(会場拍手)
司会者:ありがとうございました。せっかくの機会ですのでご質問ある方。はい。
質問者1:発表ありがとうございます。flake8とかblackとかmypyでチェックをかけるとき、tox.iniだとかsetup.cfgとかで書いていると思うんですが、それってflake8コマンドを一発で書くのか、toxでenvironを指定してflake8とかblackみたいなかたちで個別に指定する方法がいいのか。
例えばblackとmypyとflake8を一括でチェックするような設定がいいのか。flake8ならflake8であるとを一発でわかるようにしたほうがいいとか、こんなのがおすすめとかありますでしょうか。
Odagiri:toxのタスクをどう構成するかという話?
質問者1:はい。
Odagiri:大体やることは変わらないので、lintingとかそんな感じのタスクを作って、その中でもうflake8、mypy、blackみたいな感じでいっぺんに動かしちゃってますね。
質問者1:なるほど。ありがとうございます。
司会者:ほかにご質問のある方?
Odagiri:ないですかね。
司会者:はい。じゃあご質問がなければ終わりに。
Odagiri:いいですかね。一応今日PSFブースの周りをうろうろしているときであれば質問を受け付けますので、そこらへんにいたら質問してみてください。
司会者:すみません。運営関係の質問ですけど、この資料はのちほど「#pyconjp」タグでTwitterに公開されますか?
Odagiri:例年どおり。
司会者:例年どおりしていただけるということで。ありがとうございます。
Odagiri:SlideshareのアップとURLをconnpassのに上げておきます。
司会者:ありがとうございます。connpassのほうに資料のURLが上がるそうですので、復習などをしていただけたらいいんじゃないかなと思います。
とくに質問等ないようでしたら、これでビギナーセッションを終わりたいと思います。Odagiriさん、どうもありがとうございました。
(会場拍手)
関連タグ:
2025.01.09
マッキンゼーのマネージャーが「資料を作る前」に準備する すべてのアウトプットを支える論理的なフレームワーク
2025.01.16
社内プレゼンは時間のムダ パワポ資料のプロが重視する、「ペライチ資料」で意見を通すこと
2025.01.15
若手がごろごろ辞める会社で「給料を5万円アップ」するも効果なし… 従業員のモチベーションを上げるために必要なことは何か
2025.01.14
コンサルが「理由は3つあります」と前置きする理由 マッキンゼー流、プレゼンの質を向上させる具体的Tips
2025.01.07
資料は3日前に完成 「伝え方」で差がつく、マッキンゼー流プレゼン準備術
2025.01.07
1月から始めたい「日記」を書く習慣 ビジネスパーソンにおすすめな3つの理由
2025.01.10
プレゼンで突っ込まれそうなポイントの事前準備術 マッキンゼー流、顧客や上司の「意思決定」を加速させる工夫
2025.01.08
職場にいる「嫌われた上司」がたどる末路 よくあるダメな嫌われ方・良い嫌われ方の違いとは
2024.06.03
「Willハラスメント」にならず、部下のやりたいことを聞き出すコツ 個人の成長と組織のパフォーマンス向上を両立するには
2025.01.14
目標がなく悩む若手、育成を放棄する管理職… 社員をやる気にさせる「等級制度」を作るための第一歩
安野たかひろ氏・AIプロジェクト「デジタル民主主義2030」立ち上げ会見
2025.01.16 - 2025.01.16
国際コーチング連盟認定のプロフェッショナルコーチ”あべき光司”先生新刊『リーダーのためのコーチングがイチからわかる本』発売記念【オンラインイベント】
2024.12.09 - 2024.12.09
NEXT Innovation Summit 2024 in Autumn特別提供コンテンツ
2024.12.24 - 2024.12.24
プレゼンが上手くなる!5つのポイント|話し方のプロ・資料のプロが解説【カエカ 千葉様】
2024.08.31 - 2024.08.31
育て方改革第2弾!若手をつぶす等級制度、若手を育てる等級制度~等級設定のポイントから育成計画策定まで~
2024.12.18 - 2024.12.18