Kodrill

テスト・デバッグと暗号関連

Python 3 エンジニア認定実践試験

doctest・unittest・unittest.mock・pdb・timeit・logging・secrets・hashlib

問題数
16 問
合格ライン
70%
実行して確認済み
11 問
この分野の要点を読む6 章・約 14 分。実行して確かめたコード例と、試験でよくある引っかけをまとめています

ログインなしで試す

無料の 5 問を、1問ごとに正誤と解説を見ながら解けます。解答は保存されません。

5 問を試す

無料登録して学習を記録する

学習履歴・ダッシュボード・ブックマーク・模試モードが使えます。

★ 残り 11 問はプレミアム会員限定です

無料プランでは先頭 5 問まで解けます。プレミアムなら全問題・苦手問題の復習・広告非表示が使えます。
料金プランを見る

問題と解説を見る (無料)

登録しなくても、次の5問は問題文と解説をそのまま読めます。

テスト・デバッグと暗号関連の要点

内容の確認日: 2026-10-04

この分野は『Python実践レシピ』の第 16 章 (テスト・3 問)・第 17 章 (デバッグ・2 問)・第 18 章 (暗号関連・1 問) に対応し、合わせて 40 問中 6 問が出題されます (pytest・traceback・cryptography の節は出題範囲外)。

unittest の実行順や mock.patch の置き換え先、logging のレベルによる絞り込みなど、「どう動くか」を知らないと答えにくい問題が多い分野です。実際にテストを書いて動かしてみると理解が早まります。

doctest

doctest は、docstring に書いた対話モードの実行例 (>>> の行と、その下の期待する出力) を実際に実行し、出力が一致するかを確かめます。ドキュメントの例が古くなっていないかを確認するのに向いています。

doctest.testmod() はモジュール内の docstring を調べ、すべて成功すれば何も表示せず、TestResults(failed=失敗数, attempted=実行数) を返します。失敗すると、期待した出力と実際の出力を表示します。コマンドラインからは python -m doctest ファイル名 -v で実行できます。

Python
import doctest​def average(values):    """平均を返す​    >>> average([1, 2, 3])    2.0    >>> average([])    Traceback (most recent call last):        ...    ZeroDivisionError: division by zero    """    return sum(values) / len(values)​print(doctest.testmod())
ターミナル
python3 main.py
TestResults(failed=0, attempted=2)

例外が起きる例は、Traceback (most recent call last): の行と、最後の例外の行を書けば確かめられます (間のトレースバックは ... で省略できます)。

unittest

unittest.TestCase を継承したクラスを作り、test で始まるメソッドにテストを書きます。テストはメソッドごとに独立していて、1 つが失敗してもほかのテストは実行されます。

・setUp・tearDown: 各テストの前後に毎回呼ばれる ・setUpClass・tearDownClass: クラスのテストの前後に 1 回だけ呼ばれる (@classmethod を付ける) ・テストメソッドは名前の文字列順に実行される ・主な assert メソッド: assertEqual・assertTrue・assertIn・assertIsNone・assertAlmostEqual (浮動小数点数の比較)・assertRaises (例外が起きることを確かめる。with 文で使える) ・@unittest.skip("理由"): テストをスキップする

アサーションが失敗したテストは failures、テスト中に想定外の例外が起きたテストは errors として、別々に数えられます。python -m unittest で、test*.py のファイルを自動で探して実行できます。

Python
import ioimport unittest​class TestPrice(unittest.TestCase):    @classmethod    def setUpClass(cls):        print("setUpClass")​    def setUp(self):        print("setUp", self._testMethodName)​    def test_tax(self):        self.assertAlmostEqual(0.1 + 0.2, 0.3)​    def test_add(self):        self.assertEqual(1 + 1, 3)​    def test_div(self):        with self.assertRaises(ZeroDivisionError):            1 / 0​    def test_error(self):        {}["missing"]​suite = unittest.TestLoader().loadTestsFromTestCase(TestPrice)result = unittest.TextTestRunner(stream=io.StringIO()).run(suite)print(result.testsRun, len(result.failures), len(result.errors), result.wasSuccessful())
ターミナル
python3 main.py
setUpClass
setUp test_add
setUp test_div
setUp test_error
setUp test_tax
4 1 1 False

モックを使ったテスト (unittest.mock)

Mock は、呼び出されると return_value を返し、呼ばれ方を記録するオブジェクトです。外部の API やデータベースなど、テストで本物を使いにくい部分を置き換えます。

・return_value: 戻り値。side_effect: 例外を送出させる、呼ぶたびに違う値を返す (リスト)、関数で戻り値を決める ・記録: called・call_count・call_args。確認: assert_called_once_with(...)・assert_called_with(...) (最後の呼び出し) ・MagicMock: __len__ などの特殊メソッドも設定できる。未設定の属性は自動で子のモックになる ・Mock(spec=クラス): そのクラスにない属性にアクセスすると AttributeError になり、名前の誤りに気付ける

mock.patch("モジュール.名前") は、with ブロックやデコレーターを付けた関数の間だけ、指定したオブジェクトをモックに置き換えます。置き換えるのは使われている場所の名前です。from a import f で取り込んだ f を b.py で使っているなら、b.f を置き換えます。クラスの属性は mock.patch.object(クラス, "名前") でも置き換えられます。

Python
import randomfrom unittest import mock​def roll_twice():    return random.randint(1, 6) + random.randint(1, 6)​with mock.patch("random.randint", side_effect=[6, 1]) as fake:    print(roll_twice(), fake.call_count, fake.call_args)​api = mock.Mock()api.get.return_value = {"status": "ok"}api.post.side_effect = TimeoutError("timeout")print(api.get("/health")["status"])api.get.assert_called_once_with("/health")try:    api.post("/items")except TimeoutError as e:    print("例外:", e)
ターミナル
python3 main.py
7 2 call(1, 6)
ok
例外: timeout

デバッグとログ (pdb・timeit・logging)

コードの止めたい位置に組み込み関数 breakpoint() を書くと、そこで対話的なデバッガー pdb が起動します。主なコマンドは n (次の行へ)・s (関数の中に入る)・c (次のブレークポイントまで続ける)・p 式 (値を表示)・l (ソースを表示)・q (終了) です。環境変数 PYTHONBREAKPOINT=0 で breakpoint() を無効にできます。

timeit.timeit(文, number=回数) は、文を指定した回数実行した合計時間を秒で返します。timeit.repeat はそれを繰り返してリストで返します。コマンドラインからは python -m timeit "式" で計測できます。

logging のレベルは低い順に DEBUG・INFO・WARNING・ERROR・CRITICAL で、既定では WARNING 以上だけが出力されます。ログはロガーのレベルとハンドラーのレベルの両方で絞り込まれます。ロガーは logging.getLogger(__name__) でモジュールごとに取得し、出力先 (ハンドラー) と形式 (フォーマッター) はアプリケーションの側で設定します。

Python
import loggingimport sys​logger = logging.getLogger("app.worker")logger.setLevel(logging.DEBUG)handler = logging.StreamHandler(sys.stdout)handler.setLevel(logging.INFO)handler.setFormatter(logging.Formatter("%(levelname)s %(name)s: %(message)s"))logger.addHandler(handler)logger.propagate = False​logger.debug("詳細")logger.info("処理件数 %d 件", 42)try:    1 / 0except ZeroDivisionError:    logger.error("計算に失敗しました")
ターミナル
python3 main.py
INFO app.worker: 処理件数 42 件
ERROR app.worker: 計算に失敗しました

メッセージの値は logger.info("%d 件", count) のように引数で渡すと、出力されないレベルのときに文字列の組み立てが省かれます。except 節の中で logger.exception(...) を使うと、ERROR のメッセージに加えてトレースバックも出力されます。

暗号関連 (secrets・hashlib)

パスワードの再設定用のトークンなど、推測されてはいけない値は secrets モジュールで作ります。random は再現性のある疑似乱数で、セキュリティの用途には使えません。

・secrets.token_hex(n): n バイトの乱数を 16 進数の文字列で (長さは 2n 文字) ・secrets.token_urlsafe(n): URL に使える文字の文字列で ・secrets.token_bytes(n): bytes で ・secrets.choice(シーケンス): 要素を 1 つ選ぶ ・secrets.compare_digest(a, b): タイミング攻撃を防ぐ方法で比べる

hashlib はハッシュ値を計算するモジュールで、sha256 などの関数にバイト列を渡します (文字列は TypeError)。update で少しずつデータを追加でき、まとめて渡した場合と同じ結果になります。hexdigest() は 16 進数の文字列、digest() は bytes です。

Python
import hashlibimport secrets​token = secrets.token_hex(16)print(len(token), all(c in "0123456789abcdef" for c in token))​h = hashlib.sha256()for chunk in [b"hello ", b"world"]:    h.update(chunk)print(h.hexdigest() == hashlib.sha256("hello world".encode()).hexdigest())print(len(h.hexdigest()), len(h.digest()), hashlib.sha256(b"abc").hexdigest()[:16])
ターミナル
python3 main.py
32 True
True
64 32 ba7816bf8f01cfea

試験でよくある引っかけ

  • テストメソッドの実行順

    定義した順ではなく、メソッド名の文字列順に実行されます。setUp は各テストの前に毎回呼ばれます。

  • failures と errors

    アサーションの失敗は failures、想定外の例外は errors として数えられます。

  • 浮動小数点数の比較

    assertEqual(0.1 + 0.2, 0.3) は失敗します。assertAlmostEqual を使います。

  • mock.patch の置き換え先

    定義された場所ではなく、使われている場所の名前を置き換えます。

  • side_effect のリスト

    呼ぶたびにリストの値を順に返し、要素が例外ならそれを送出します。

  • ロガーとハンドラーのレベル

    ロガーが DEBUG を受け付けても、ハンドラーが INFO なら DEBUG のログは出力されません。

  • random をトークンに使わない

    推測されてはいけない値は secrets で作ります。

  • hashlib に文字列を渡す

    ハッシュ関数は bytes を受け取ります。文字列は encode() してから渡します。

問題で確認する

この分野の問題を、解説つきで読めます (登録不要)。

出典・参考

コード例は、実際に実行して結果を確認しています。