ardggy's blog

Esc - Meta - Alt - Ctrl - Shift

doctest 駆動 AtCoder

AtCoder を始めた。ためしに Haskell や Nim で解いたりしていたが、結局は Python3 に落ち着いた。

解くのはいいが、サンプルのテストが面倒でしょうがない。TDD でできるといいが、フレームワークほどの仕組みは必要なさそう。その点で doctest はよかった。プログラムに埋め込めて、テスト実行も $ python -mdoctest XXX.py で済む。エイリアスalias t='python -mdoctest' としておけば t XXX.py だけでテストが走る。

テンプレートはいろいろ調整して以下のようになった。 as_input の仕組みは他の Pythonista の回答を参考にさせていただいた。main 関数の引数がいびつだが、Fail 時にどのケースで失敗したかがわかるのでこうしている。このまま提出しても問題ないようになっている。

#!/usr/bin/env python

def main(_=0):   # 引数はとくに使わない。`as_input` を受け入れるためだけ
    N = int(input())
    print(N * (N + 1) // 2)

# string でテストケースを与えると stdin のように振る舞ってくれる
def as_input(s: str) -> None:
    import io
    global input
    f = io.StringIO(s)
    input = lambda: f.readline().rstrip()
    return None

sample1 = """5
"""
sample2 = """100
"""
def test():
    """
    >>> main(as_input(sample1))
    15
    >>> main(as_input(sample2))
    5050
    """
    pass

if __name__ == '__main__':
    main()

結果は (doctest -v) でこんなかんじにでてくれる。

$ alias t='python -mdoctest'
$ t -v test.py
Trying:
    main(as_input(sample1))
Expecting:
    15
ok
Trying:
    main(as_input(sample2))
Expecting:
    5050
ok
3 items had no tests:
    test
    test.as_input
    test.main
1 items passed all tests:
   2 tests in test.test
2 tests in 6 items.
2 passed and 0 failed.
Test passed.

解が浮動小数点の場合、とりあえずサンプルは実行するが、どうせ間違っているので目視でなんとなくあっていれば出している(適当)