PyLadies Tokyo Meetup #29 に参加してきました

Pythonでの実務経験がなく、
実際にどのようにテストコードを書いているのか知りたくて
勉強会に参加させて頂きました。



pyladies-tokyo.connpass.com






おおまかな流れ









テストの基本について



テストをする理由や、必要なテスト項目の作成方法を教えてくださりました。
テストコードを実際に書いて説明してくださった場面もあっため、
どういう手順でテストを書くのか知ることができました。

「1テストで1観点」をしっかり意識して、今後テストを書いていこうと思います。

ちなみに、PyCharmでoption + command + mと打つとメソッド切り出しができるといった、
ショートカットの小技を教えてもらうこともできました。



テストをする理由




  • バグの発見


  • 品質の担保


  • 不明確な仕様を詰める








Pythonでの単体テストについて



Pythonのテストをする上で参考になる書籍や、テストモジュール、
演習問題など詳細に教えてくださったので、とても勉強になりました。



テスト駆動開発



テスト駆動開発』でのテスト作成方法を、コードを書きながら説明してくださったので非常にわかりやすかったです。
テスト駆動開発では、テストを先に書いてからプログラムを作成するので、
プログラムの完成と同時にテストができあがります。
そうすることでテスト漏れがなくなりますし、テストを書く時間がないといったこともなくなるようです。

テスト → 実装 → リファクタ という流れです。

私はテスト駆動開発のことは知っていましたが、いつも実装から書いていたので、
テスト駆動開発のメリットを知る良い機会だと思って今後はテストから書いていこうと思いました。



「テストしやすいプログラムを書く」ということも印象的で、
特有の機能は関数化する、関数が持つ機能は1つにする、といったことは大切だと改めて思いました。






テストモジュールについて



unittestしか知らず、業務でよく使われているモジュールに興味があったので、知ることができて嬉しかったです。
テストモジュールの詳細については「Python ライブラリ厳選レシピ」に書いてあるそうです。



Python ライブラリ厳選レシピ

Python ライブラリ厳選レシピ







  • doctest




標準ライブラリに入っています。
インタプリタ形式でテストを実行します。

失敗するとエラーが表示され、成功すると何も表示されません。

コメントに少し書くだけでテストができるのでとても便利です。




  • unittest




標準ライブラリに入っています。

TestCaseを継承して使います。




  • pytest




モジュールなのでpipして使います。

ファイル名にtestをつけると自動で探してテストを実行してくれます。

unittestよりもエラーの表示が親切で、コードのどこの部分でエラーになったか表示してくれます。






ハンズオン



PyCharm(無償版)でテストコードを書いたのですが、
実行ボタンを押してもテストが上手く読み込まれない事象が発生しました。
@maaya8585 さんに教えて頂き、下記設定をすることでテストを実行できるようになりました。
Targetの項目は、対象のテストクラスを指定します。

ご丁寧に教えて頂きありがとうございました!



f:id:mtomitomi:20180223090204p:plain






f:id:mtomitomi:20180223090216p:plain






演習問題






unittestとpytestの両方を使ってみました。

初心者の私にとってはunittestのほうが使いやすかったですが、
コードの綺麗さや可読性ではpytestのほうが良さそうでした。



unittest




"""
世界のナベアツ
・数字を渡すと、渡した数字を文字列で返す
・3の倍数のときは阿呆になるので、「さぁ〜ん」と文字列を返す
・渡した数字に3が含まれるときは阿呆になるので、「さぁ〜ん」と文字列を返す
"""
from unittest import TestCase


def aho_three(num):
"""3の倍数と、3の値がつくときだけアホになる関数"""
if num % 3 == 0 or "3" in str(num):
return "さぁ〜ん"
else:
return str(num)


class Test(TestCase):

def test_aho1(self):
"""1を渡したら1を返すテスト"""
expected = "1"
actual = aho_three(1)

self.assertEquals(expected, actual)

def test_aho2(self):
"""3の倍数でアホになるテスト"""
expected = "さぁ〜ん"
actual = aho_three(6)

self.assertEquals(expected, actual)

def test_aho3(self):
"""3がつく数字でアホになるテスト"""
expected = "さぁ〜ん"
actual = aho_three(13)

self.assertEquals(expected, actual)





<実行結果>



f:id:mtomitomi:20180223153606p:plain





<失敗した場合>



f:id:mtomitomi:20180223153713p:plain





pytest



pytestで書いたテストコードをPyCharmで実行しても読み込まれなかったのですが、
unittestと同様の設定をしたら実行できました。
Targetについてですが、pytestではTestクラスを作成していないので、メソッド名を指定しました。



f:id:mtomitomi:20180223153138p:plain







def aho_three(num):
"""3の倍数と、3の値がつくときだけアホになる関数"""
if num % 3 == 0 or "3" in str(num):
return "さぁ〜ん"
else:
return str(num)


def test_aho1():
"""1を渡したら1を返すテスト"""
expected = "1"
actual = aho_three(1)

assert expected == actual


def test_aho3():
"""3の倍数でアホになるテスト"""
expected = "さぁ〜ん"
actual = aho_three(6)

assert expected == actual


def test_aho4():
"""3がつく数字でアホになるテスト"""
expected = "さぁ〜ん"
actual = aho_three(13)

assert expected == actual






<実行結果>



f:id:mtomitomi:20180223153346p:plain





<失敗した場合>

unittestと比較してみましたら、pytestはExpectedActualが明記されていて、
この点だけpytestのほうがわかりやすかったですが、他は同じようでした。



f:id:mtomitomi:20180223153459p:plain





ちなみに<Click to see difference>のリンクをクリックすると
期待値と結果を左右で比較することができます。



f:id:mtomitomi:20180223154053p:plain







  • フィボナッチ数プログラム




unittestのみで書きました。




"""
フィボナッチ数を返却する
・fib(0) = 0
・fib(1) = 1
・fib(n+2) = fib(n) + fib(n+1) (n ≧ 0)
"""

from unittest import TestCase


def fib(num):
if num == 0 or num == 1:
return num
else:
return fib(num - 1) + fib(num - 2)


class Test(TestCase):

def test_fib1(self):
"""0を渡したら0を返すテスト"""
expected = 0
actual = fib(0)
self.assertEquals(expected, actual)

def test_fib2(self):
"""1を渡したら1を返すテスト"""
expected = 1
actual = fib(1)
self.assertEquals(expected, actual)

def test_fib3(self):
"""2を渡したら1を返すテスト"""
expected = 1
actual = fib(2)
self.assertEquals(expected, actual)

def test_fib4(self):
"""10を渡したら55を返すテスト"""
expected = 55
actual = fib(10)
self.assertEquals(expected, actual)





書いたコードはgithubにあげておきました。



github.com






感想



講義の資料がとてもわかりやすかったですし、
実際にコードを書いてくださることで書き方がわかったので学ぶことも多かったです。
また、参考になる書籍やURLなど多くの情報を頂いたので、読んでみようと思っています。



仕事でJavaのテストコードを書いた経験はありますが、
改めてテストの大切さを実感しましたし、
社外でのテスト技法を知ることができて新鮮でした。
品質を保証するためにも自分を守るためにも、必要なテストコードを書いて
バグのないプログラムを作っていきたいと思います。





今までPyLadiesのイベントは週末開催のしか参加したことがなかったのですが、
2時間の間に大事なことが濃縮されていてとても勉強になりました。

管理者の皆さま、講義をしてくださった皆さま、お忙しいなか本当にありがとうございました!

また参加させて頂きたいと思っていますので、よろしくお願いします。