Pythonのテストツールdoctestを使ってみよう
doctestによるテスト
doctestモジュールは、コードの中でPythonのインタラクティブなセッションに似たテキストを検索します。そして、それらのセッションを実行して、書かれている通りに動作するかどうかを検証します。これは、もしあなたが docstring の中で、出力の末尾にスペースやタブを入れた例を書いているのであれば、その関数の実際の出力にも末尾にホワイトスペースを入れなければならないということです。ほとんどの場合、テストは docstring に記述されます。
doctest は次の3つの方法で実行されます。
ターミナルから doctest を実行する
モジュール内での doctest の使用する
別のファイルから doctest を実行する
ターミナルから doctest を実行する
次のようなコードで説明していきましょう。
code: 01_fibo.py
def fibo(n):
if n == 0 or n == 1:
return 1
else:
return fibo(n-1) + fibo(n-2)
if __name__ == '__main__':
v = fibo(10)
print(v)
この例の fino()関数には docstring が定義されていません。
この状態では、doctest を実行してもテストが記述されていないため、テストは実施されません。
code: bash
$ python -m doctest -v s01_fibo.py
2 items had no tests:
01_fibo
s01_fibo.fibo
0 tests in 2 items.
0 passed and 0 failed.
Test passed.
-m doctest には -vオプションを与えることができ、詳細がテスト結果を表示します。これを省略すると、テストに失敗したときだけ出力されるようになります。
コードにテストを記述してみましょう。
code: s02_fibo.ppy
def fibo(n):
"""
>> fibo(8)
34
>> fibo(9)
55
"""
if n == 0 or n == 1:
return 1
else:
return fibo(n-1) + fibo(n-2)
if __name__ == '__main__':
v = fibo(10)
print(v)
PythonのREPLでfibo() を 引数 8 と 9 で呼び出した結果をテストとして記述しています。
doctest を実行してみましょう。
code: bash
% python -m doctest -v s02_fibo.py
Trying:
fibo(8)
Expecting:
34
ok
Trying:
fibo(9)
Expecting:
55
ok
1 items had no tests:
s02_fibo
1 items passed all tests:
2 tests in s02_fibo.fibo
2 tests in 2 items.
2 passed and 0 failed.
Test passed.
2つのテストが実施されて失敗しなかった(0 failed)ことがわかります。
-v オプションをつけずに起動すると次のようになります。
code: bash
$ python -m doctest s02_fibo.py
これでテストが実行されましたが、スクリーンには何もプリントアウトされませんでした。何も印刷されないということは、すべてのテストが失敗しなかったということです。テストに失敗すると終了コードが 1 になるため、シェルの機能を使用して次のように起動することもできます。
失敗したときに Filed と表示させる例
code: bash
$ python -m doctest s02_fibo.py || echo Failed
$
成功したときに Success と表示させる例
code: bash
$ python -m doctest s02_fibo.py && echo Success
Success
今度はテストを意図的に失敗させてみましょう。fibo(8)の結果となる34の後ろに空白文字をひとつ入れてみましょう。
code: bash
% diff -Nru s02_fibo.py s03_fibo_bad.py
--- s02_fibo.py 2021-11-09 15:52:41.000000000 +0900
+++ s03_fibo_bad.py 2021-11-10 08:52:01.000000000 +0900
@@ -1,7 +1,7 @@
def fibo(n):
"""
>> fibo(8)
- 34
+ 34
>> fibo(9)
55
"""
doctest を実行してみます。
code: bash
% python -m doctest s03_fibo_bad.py
**********************************************************************
File "s03_fibo_bad.py", line 3, in s03_fibo_bad.fibo
Failed example:
fibo(8)
Expected:
34
Got:
34
**********************************************************************
1 items had failures:
1 of 2 in s03_fibo_bad.fibo
***Test Failed*** 1 failures.
テストは、34 を期待していたのに、34 が得られたとして表示してエラーになっています。
見た目には違いがわかりませんが、"34" と "34 " は異なるため、テストに失敗しているわけです。
余談
本題からずれるため詳細な説明はいたしませんが、
Linux で vim エディタを使用している場合は、次の行を ~/.vimrc に設定すると、保存時に行末の空白を削除してくれます。
autocmd BufWritePre * :%s/\s\+$//ge
他のエディタやIDEでの同類の設定や追加機能があるはずです。
モジュール内での doctest の使用する
doctestモジュールをインポートして、testmod()関数を呼び出すことで doctest を実行することができます。
code: s04_inide_module.py
def fibo(n):
"""
>> fibo(8)
34
>> fibo(9)
55
"""
if n == 0 or n == 1:
return 1
else:
return fibo(n-1) + fibo(n-2)
if __name__ == '__main__':
import doctest
doctest.testmod(verbose=True)
この例ではキーワード引数 verbose=True を渡しています。これは、コマンドラインでの、-vオプションと同じ動作をさせるもので、何らかの出力をさせるようにしています。そうしないと、実行してもこのスクリプトは何の出力もされません。
verbose引数をハードコーディングしたくない場合は、コマンドラインで指定することもできます。
code: bash
$ python s04_inside_module.py -v
別のファイルから doctest を実行する
doctest は、テストを別のファイルに保存することもサポートしているため、テストとコードから分離することができます。先ほどの例からテストを抜き出して、tests.txt というテキストファイルに入れてみましょう。
code: tests.txt
>> from s01_fibo import fibo
>> fibo(8)
34
>> fibo(9)
55
tests.txt を doctest で呼び出す方法は、Pythonファイルを指定する場合と変わりありません。
code: bash
$ python -m doctest -v tests.txt
Trying:
from s01_fibo import fibo
Expecting nothing
ok
Trying:
fibo(8)
Expecting:
34
ok
Trying:
fibo(9)
Expecting:
55
ok
1 items passed all tests:
3 tests in tests.txt
3 tests in 1 items.
3 passed and 0 failed.
Test passed.
ファイル名の拡張子が .py でないので、 doctest は testmod() ではなく testfile() を使って実行します。
テストの結果も同じです。この例の場合、モジュールをインポートしているので、テストは2つではなく3つになります。
テキストファイルtests.txt にあるテストをPythonインタープリタ内で実行することもできます。
code: python
% python
Python 3.9.7 | packaged by conda-forge | (default, Sep 29 2021, 19:23:19)
Type "help", "copyright", "credits" or "license" for more information.
>> import doctest
>> doctest.testfile('tests.txt')
TestResults(failed=0, attempted=3)
>>
IPython の場合は少し注意する必要があります。デフォルトでは ipython が配置されているディレクトリからの相対パスとして、tests.txt を探そうとします。
code: python
In 2: doctest.testfile('tests.txt') ---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-2-40825d1b78fa> in <module>
----> 1 doctest.testfile('tests.txt')
(中略)
FileNotFoundError: Errno 2 No such file or directory: '/Users/goichiiisaka/anaconda3/envs/tutorials/bin/tests.txt' IPython では、testfile()にmodule_relative=False を与えて実行します。
code: python
In 2: result = doctest.testfile('tests.txt', module_relative=False) Out3: TestResults(failed=0, attempted=3) doctestをインポートして,そのtestfile()関数を呼び出すだけです。testfile() 関数には、ファイル名やパスも渡す必要があることに注意してください。この関数はTestResultsオブジェクトを返し、その中にはいくつのテストが試みられ、いくつが失敗したかが含まれています。
余談
テストファイルを指示するためにOS固有のパス区切り文字を使用したいときも、module_relative=False とする必要があります。この場合、テストファイルのパスは、絶対パスでも、(現在の作業ディレクトリに対する)相対パスでも構いません。
doctest でのテストの記述方法
とんどの場合、対話コンソールセッション上でのコピー/ペーストはうまく動作します。ただし、次のような制約が
あります。
期待する出力結果には、空白だけの行を書いてはいけない。そのような行は期待する出力結果の終了と見なされます。もし期待する出力結果の内容に空白行が入っている場合には、空白行が入るべき場所すべてに <BLANKLINE> と記述します。
全てのタブ文字は 8 カラムのタブ位置でスペースに展開されます。テスト対象のコードが作成した出力にあるタブは変更されません。出力例にあるどんなタブも展開 される ので、コードの出力がハードタブを含んでいた場合、 doctest が通るには NORMALIZE_WHITESPACE オプションか directive を有効にするしかありません。
標準出力への出力は取り込まれますが、標準エラーは取り込まれません。
対話セッションにおいて、バックスラッシュを用いて次の行に続ける場合や、その他の理由でバックスラッシュを用いる場合、raw docstring を使ってバックスラッシュを入力どおりに扱わせるようにしなければなりません
doctest API
doctest APIは、docstringからインタラクティブな例を保存するために使用される以下の2つのコンテナクラスが中心になります。
DocTest:1つのPythonステートメントと、その期待される出力のペア。
Example: 典型的には一つの docstring やテキストファイルから抽出された例題のコレクション。
次のクラスは、doctestの例を見つけ、解析し、実行し、チェックするために定義されています。
DocTestFinder: 与えられたモジュール内の全てのdocstringを見つけ、DocTestParserを使って、インタラクティブな例を含む全てのdocstringからDocTestを作成します。
DocTestParser: 文字列(オブジェクトのdocstringなど)からdoctestオブジェクトを作成します。
DocTestRunner: doctest 内のサンプルを実行し、OutputChecker を使用してその出力を検証します。
OutputChecker: doctest の例からの実際の出力を期待される出力と比較し、それらが一致するかどうかを判断します。
DocTestFinder クラス
DocTestFinderクラスは、あるオブジェクトのdocstringと、そのオブジェクトに含まれるオブジェクトのdocstringから、そのオブジェクトに関連するdoctestを抽出するための処理クラスです。現在、モジュール、関数、クラス、メソッド、スタティックメソッド、クラスメソッド、プロパティなどのオブジェクトタイプからDocTestを抽出することができます。
このクラスでは、find()メソッドを定義しています。このクラスは、オブジェクトのdocstring、または含まれるオブジェクトのdocstringで定義されたDocTestのリストを返します。
DocTestParser クラス
文字列から対話型の例題を抽出し、それをもとにDocTestオブジェクトを作成するための処理クラスです。このクラスは以下のメソッドを定義しています。
get_doctest():与えられた文字列からすべてのdoctest例を抽出し、DocTestオブジェクトに集めます。
get_examples(string[, name]):与えられた文字列からすべてのdoctestの例を抽出し、Exampleオブジェクトのリストとして返します。行番号は0ベースです。オプションの引数 name は、この文字列を識別する名前で、エラーメッセージにのみ使用されます。
parse(string[, name]):与えられた文字列を例題とその間のテキストに分割し、それらを例題と文字列を交互に並べたリストとして返します。例題の行番号は0ベースです。オプションの引数nameは、この文字列を識別する名前で、エラーメッセージにのみ使用されます。
DocTestRunner クラス
DocTest 内のインタラクティブなサンプルを実行し、検証するための処理クラスです。以下のメソッドが定義されています。
report_start():テストランナーが指定された例の処理を開始することを報告します。このメソッドは、DocTestRunner のサブクラスが出力をカスタマイズするために提供されています。
report_success():与えられたサンプルの実行が成功したことを報告します。このメソッドは、DocTestRunner のサブクラスがその出力をカスタマイズできるように提供されています; 直接呼び出してはいけません。
report_failure():与えられた例が失敗したことを報告します。このメソッドは、DocTestRunner のサブクラスがその出力をカスタマイズできるように提供されています; 直接呼び出してはいけません。
report_unexpected_exception():与えられた例が予期せぬ例外を発生させたことを報告します。このメソッドは、DocTestRunnerのサブクラスがその出力をカスタマイズできるように提供されています。直接呼び出してはいけません。
run(test):test(DocTestオブジェクト)内の例題を実行し、ライター関数outを使って結果を表示します。
summarize([verbose]):この DocTestRunner で実行されたすべてのテストケースの概要を印刷し、名前付きタプル TestResults(failed, attempted) を返します。オプションの verbose 引数は、サマリーの詳細度を制御します。verbosity が指定されていない場合は、DocTestRunner の verbosity が使用されます。
OutputChecker クラス
このクラスは、Doctest のサンプルからの実際の出力が、期待される出力と一致するかどうかをチェックするために使用されます。
このクラスには、以下のメソッドが定義されています。
check_output():例題からの実際の出力(get)が、期待される出力(want)と一致した場合にTrueを返します。しかし、テストランナーが使用しているオプションフラグに応じて、 いくつかの非正確なマッチタイプも可能です。オプションフラグについての詳細は オプションフラグとディレクティブ を参照ください。
output_difference():与えられた例に対して期待される出力 (example) と実際の出力 (got) の違いを表す文字列を返します。
オプションフラグ
doctest の振る舞いは、数多くのオプションフラグによって様々な側面から制御されています。フラグのシンボル名はモジュールの定数として提供され、 ビット単位論理和 でつないで様々な関数に渡すことができます。シンボル名は doctest directives でも使用でき、doctest コマンドラインインターフェースに -oオプションを通して与えることができます。 最初に説明するオプション群は、テストのセマンティクスを決めます。すなわち、実際にテストを実行したときの出力と実行例中の期待する出力とが一致しているかどうかを doctest がどのように判断するかを制御します:
doctest.DONT_ACCEPT_TRUE_FOR_1
デフォルトでは、期待する出力ブロックに単に 1 だけが入っており、実際の出力ブロックに 1 または True だけが入っていた場合、これらの出力は一致しているとみなされます。 0 と False の場合も同様です。 DONT_ACCEPT_TRUE_FOR_1 を指定すると、こうした値の読み替えを行いません。デフォルトの挙動で読み替えを行うのは、最近の Python で多くの関数の戻り値型が整数型からブール型に変更されたことに対応するためです; 読み替えを行う場合、"通常の整数" の出力を期待する出力とするような doctest も動作します。このオプションはそのうちなくなるでしょうが、ここ数年はそのままでしょう。
doctest.DONT_ACCEPT_BLANKLINE
デフォルトでは、期待する出力ブロックに <BLANKLINE> だけの入った行がある場合、その行は実際の出力における空行に一致するようになります。完全な空行を入れてしまうと期待する出力がそこで終わっているとみなされてしまうため、期待する出力に空行を入れたい場合にはこの方法を使わなければなりません。 DONT_ACCEPT_BLANKLINE を指定すると、 <BLANKLINE> の読み替えを行わなくなります。
doctest.NORMALIZE_WHITESPACE
このフラグを指定すると、連続する空白 (空白と改行文字) は互いに等価であるとみなします。期待する出力における任意の空白列は実際の出力における任意の空白と一致します。デフォルトでは、空白は厳密に一致しなければなりません。 NORMALIZE_WHITESPACE は、期待する出力の内容が非常に長いために、ソースコード中でその内容を複数行に折り返して書きたい場合に特に便利です。
doctest.ELLIPSIS
このフラグを指定すると、期待する出力中の省略記号マーカ (...) が実際の出力中の任意の部分文字列と一致するようになります。部分文字列は行境界にわたるものや空文字列を含みます。したがって、このフラグを使うのは単純な内容を対象にする場合にとどめましょう。複雑な使い方をすると、正規表現に .* を使ったときのように "しまった、マッチしすぎた! (match too much!)" と驚くことになりかねません。
doctest.IGNORE_EXCEPTION_DETAIL
このフラグを指定すると、期待する実行結果に例外が入るような実行例で、期待通りの型の例外が送出された場合に、例外の詳細情報が一致していなくてもテストが成功します。例えば、期待する出力が ValueError: 42 であるような実行例は、実際に送出された例外が ValueError: 3*14 でも成功しますが、 TypeError が送出されるといった場合には成功しません。
code: python
>> raise CustomError('message')
Traceback (most recent call last):
CustomError: message
>> raise CustomError('message')
Traceback (most recent call last):
my_module.CustomError: message
なお、 ELLIPSIS を使っても例外メッセージの詳細を無視することができますが、モジュールの詳細が例外名の一部として表示されるかどうかに依存するようなテストは、やはり失敗します。
doctest.SKIP
このフラグを指定すると、実行例は一切実行されません。こうした機能は doctest の実行例がドキュメントとテストを兼ねていて、ドキュメントのためには含めておかなければならないけれどチェックされなくても良い、というような文脈で役に立ちます。例えば、実行例の出力がランダムであるとか、テストドライバーには利用できないリソースに依存している場合などです。
SKIP フラグは一時的に実行例を"コメントアウト"するのにも使えます。
doctest.COMPARISON_FLAGS
上記の比較フラグすべての論理和をとったビットマスクです。
二つ目のオプション群は、テストの失敗を報告する方法を制御します:
doctest.REPORT_UDIFF
このオプションを指定すると、期待する出力および実際の出力が複数行になるときにテストの失敗結果を unified diff 形式を使って表示します。
doctest.REPORT_CDIFF
このオプションを指定すると、期待する出力および実際の出力が複数行になるときにテストの失敗結果を context diff 形式を使って表示します。
doctest.REPORT_NDIFF
このオプションを指定すると、期待する出力と実際の出力との間の差分を difflib.Differ を使って算出します。使われているアルゴリズムは有名な ndiff.py ユーティリティと同じです。これは、行単位の差分と同じように行内の差分にマーカをつけられるようにする唯一の手段です。例えば、期待する出力のある行に数字の 1 が入っていて、実際の出力には l が入っている場合、不一致の起きているカラム位置を示すキャレットの入った行が一行挿入されます。
doctest.REPORT_ONLY_FIRST_FAILURE
このオプションを指定すると、各 doctest で最初にエラーの起きた実行例だけを表示し、それ以後の実行例の出力を抑制します。これにより、正しく書かれた実行例が、それ以前の実行例の失敗によっておかしくなってしまった場合に、 doctest がそれを報告しないようになります。とはいえ、最初に失敗を引き起こした実行例とは関係なく誤って書かれた実行例の報告も抑制してしまいます。 REPORT_ONLY_FIRST_FAILURE を指定した場合、実行例がどこかで失敗しても、それ以後の実行例を続けて実行し、失敗したテストの総数を報告します; 出力が抑制されるだけです。
doctest.FAIL_FAST
このオプションを指定すると、最初に実行例が失敗した時点で終了し、残りの実行例を実行しません。つまり、報告される失敗の数はたかだか 1 つになります。最初の失敗より後の例はデバッグ出力を生成しないため、このフラグはデバッグの際に有用でしょう。
doctest コマンドラインは -f を -o FAIL_FAST の短縮形として受け付けます。
doctest.REPORTING_FLAGS
上記のエラー報告に関するフラグすべての論理和をとったビットマスクです。
サブクラス化で doctest 内部を拡張するつもりがなければ役に立ちませんが、別の新しいオプションフラグ名を登録する方法もあります:
doctest.register_optionflag(name)
名前 name の新たなオプションフラグを作成し、作成されたフラグの整数値を返します。 register_optionflag() は OutputChecker や DocTestRunner をサブクラス化して、その中で新たに作成したオプションをサポートさせる際に使います。 register_optionflag() は以下のような定形文で呼び出さなければなりません:
code: python
MY_FLAG = register_optionflag('MY_FLAG')
ディレクティブ (Directives)
doctest ディレクティブは個々の実行例の オプションフラグ を操作するために使われます。 doctest ディレクティブは後のソースコード例にあるような特殊な Python コメントです:
code: python
directive ::= "#" "doctest:" directive_options
directive_options ::= directive_option ("," directive_option)\*
directive_option ::= on_or_off directive_option_name
on_or_off ::= "+" \| "-"
directive_option_name ::= "DONT_ACCEPT_BLANKLINE" \| "NORMALIZE_WHITESPACE" \| ...
+ や - とディレクティブオプション名の間に空白を入れてはなりません。ディレクティブオプション名は上で説明したオプションフラグ名のいずれかです。
ある実行例の doctest ディレクティブは、その実行例だけの doctest の振る舞いを変えます。ある特定の挙動を有効にしたければ + を、無効にしたければ - を使います。
code: python
>> print(list(range(20)))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
ディレクティブがない場合、実際の出力には一桁の数字の間に二つスペースが入っていないこと、実際の出力は 1 行になることから、テストは成功しないはずです。別のディレクティブを使って、このテストを成功させることもできます:
doctest では、期待する出力に対する完全一致を厳格に求めます。 一致しない文字が一文字でもあると、テストは失敗してしまいます。 このため、 Python が出力に関して何を保証していて、何を保証していないかを正確に知っていないと混乱させられることがあるでしょう。
DocTest と Unittest の統合
doctest モジュールは、doctest を含むモジュールやテキストファイルから unittest テストスイートを作成するために使用できる 2 つの関数を提供しています。unittest テストディスカバリーと統合するには、テストモジュールに load_tests() 関数を組み込んでください。
code: python
import unittest
import doctest
import doctestexample
def load_tests(loader, tests, ignore):
tests.addTests(doctest.DocTestSuite(doctestexample))
return tests
unittest と doctest のテストを組み合わせた TestSuite が生成され、unittest モジュールの main() メソッドや run() メソッドで実行できるようになります。
テキストファイルとdoctests-モジュールから unittest.TestSuite インスタンスを生成する主な機能は以下の2つです。
doctest.DocFileSuite()
1つまたは複数のテキストファイルからdoctestのテストをunittest.TestSuiteに変換するために使用されます。返された unittest.TestSuite は unittest フレームワークによって実行され、各ファイルのインタラクティブな例を実行します。ファイル内の例題のいずれかが失敗した場合、合成されたユニットテストは失敗し、テストを含むファイルの名前と(時にはおおよその)行番号を示すfailureException例外が発生します。
doctest.DocTestSuite()
これは、モジュールの doctest テストを unittest.TestSuite に変換するために使用されます。
返された unittest.TestSuite は unittest フレームワークによって実行され、モジュール内の各 doctest を実行します。いずれかのdoctestが失敗した場合、合成されたユニットテストは失敗し、テストを含むファイルの名前と(時には近似した)行番号を示すfailureException例外が発生します。
カバーの下では、DocTestSuite() は doctest.DocTestCase インスタンスから unittest.TestSuite を作成し、DocTestCaseクラス は unittest.TestCase のサブクラスとなります。
同様に、DocFileSuite() は doctest.DocFileCase インスタンスから unittest.TestSuite を作成し、DocFileCaseクラス は DocTestCase のサブクラスとなります。
つまり、unittest.TestSuiteを作成する両方の方法で、DocTestCaseのインスタンスを実行します。doctest 関数を自分で実行する場合、オプションフラグを doctest 関数に渡すことで、使用する doctest オプションを直接制御することができます。
しかしながら、 unittest フレームワークを書いている場合には、いつどのようにテストを動作させるかを unittest が完全に制御してしまいます。フレームワークの作者はたいてい、 doctest のレポートオプションを (コマンドラインオプションで指定するなどして) 操作したいと考えますが、 unittest を介して doctest のテストランナーにオプションを渡す方法はありません。
このため、 doctest では、以下の関数を使って、 unittest サポートに特化したレポートフラグ表記方法もサポートしています:
doctest.set_unittest_reportflags(flags)
doctest のレポートフラグをセットします。
引数 flags はオプションフラグの ビット単位論理和 を取ります。 オプションフラグ 節を参照してください。「レポートフラグ」しか使えません。
この関数で設定した内容はモジュール全体にわたるものであり、関数呼び出し以後に unittest モジュールから実行されるすべての doctest に影響します: DocTestCase の runTest() メソッドは、 DocTestCase インスタンスが作成された際に、現在のテストケースに指定されたオプションフラグを見に行きます。レポートフラグが指定されていない場合 (通常の場合で、望ましいケースです)、 doctest の unittest レポートフラグが bit ごとの OR で結合され、doctest を実行するために作成される DocTestRunner インスタンスに渡されます。 DocTestCase インスタンスを構築する際に何らかのレポートフラグが指定されていた場合、 doctest の unittest レポートフラグは無視されます。
この関数は、関数を呼び出す前に有効になっていた unittest レポートフラグの値を返します。
doctest の利用方法
doctest をテスト駆動開発(Test-Driven Development; TDD) のためのツールとして利用しましょう。関数の仕様(入力と出力)を設計するときに、関数の使用例を例示するためテストを記述しておきます。このテストが通るように関数を開発を進めることです。コードを書くことで具体化していきながら、開発を進めることができます。
テストを作成する場合では、次のことも重要になります。
成功するテストだけでなく、失敗するテストも書いておくようにしましょう。
テストを最初から完全なものにしようとしない。ここでのテストは品質のためのものではなく、開発やコードの説明に寄与するもの。コードの開発が進んで行く過程でテストを書き直す方がよいこともあるためため、早い段階でコードとテストを分離するべきではありません。
テストは必ず実施するようにしましょう。開発初期の段階では、単にハードコーディングした値を返すなど、どんなことをしてもよいので、とにかくテストをパスするコードを積み上げてゆくことです。
参考
Python 公式ドキュメント