Stay Hungry,Stay Foolish!

pytest solution for argparse application

背景

pytest属于单元测试, 测试对象为模块函数,

对于argparse应用,需要带有参数进行测试的情况,

是否也可以将其对待为函数,带有测试的参数?

答案是可以的。

 

Example

https://github.com/simonw/stream-delay/tree/0.1

例如, 此package提供了如下参数能力。

如何对这些参数进行测试?

Examples:

  • cat myfile.txt | stream-delay - will stream from that file with a 100ms delay between each line
  • stream-delay myfile.txt - same as above, this time using the filename
  • stream-delay myfile.txt myfile2.txt - streams from the first file, then the second file
  • stream-delay myfile.txt -d 1000 - streams from that file with a one second delay between each line

 

主程序:

https://github.com/simonw/stream-delay/blob/0.1/stream_delay.py

应用定义的main函数,需要带有入参args, 此入参即为 sys.argv[1:]

argparse进行解析的时候,传入args

parser.parse_args(args)

import argparse, sys, time

parser = argparse.ArgumentParser(
    description="Stream one or more files with a delay between each line"
)
parser.add_argument("files", type=argparse.FileType("r"), nargs="*", default=["-"])
parser.add_argument("-d", "--delay-in-ms", type=int, default=100)


def main(args=None):
    parsed_args = parser.parse_args(args)
    delay_in_s = float(parsed_args.delay_in_ms) / 1000
    for file in parsed_args.files:
        if file == "-":
            file = sys.stdin
        for line in file:
            sys.stdout.write(line)
            sys.stdout.flush()
            time.sleep(delay_in_s)


if __name__ == "__main__":
    main()

 

测试代码:

https://github.com/simonw/stream-delay/blob/0.1/tests/test_stream_delay.py

测试代码组织 argv,传入main函数

from stream_delay import main
import pytest
import time


@pytest.mark.parametrize("option", ("-h", "--help"))
def test_help(capsys, option):
    try:
        main([option])
    except SystemExit:
        pass
    output = capsys.readouterr().out
    assert "Stream one or more files with a delay" in output


@pytest.mark.parametrize("delay", (None, "-d", "--delay-in-ms"))
def test_with_delay(tmpdir, capsys, delay):
    three_lines = str(tmpdir / "three_lines.txt")
    open(three_lines, "w").write("one\ntwo\nthree")
    start = time.time()
    args = [three_lines]
    if delay:
        args += [delay, "500"]
    try:
        main(args)
    except SystemExit:
        pass
    end = time.time()
    duration = (end - start) * 1000
    output = capsys.readouterr().out
    assert output == "one\ntwo\nthree"
    expected = 300
    if delay:
        expected = 1500
    assert (expected - 50) < duration < (expected + 50)

 

posted @ 2022-10-28 23:59  lightsong  阅读(118)  评论(0编辑  收藏  举报
Life Is Short, We Need Ship To Travel