Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pytest 笔记 #2

Open
copie opened this issue Oct 23, 2018 · 0 comments
Open

pytest 笔记 #2

copie opened this issue Oct 23, 2018 · 0 comments
Labels

Comments

@copie
Copy link
Owner

copie commented Oct 23, 2018

pytest 笔记

  • 使用 assert 进行断言

  • 使用 pytest file1.py file2.py 去测试一个单独的文件

  • 使用 pytest filepath 测试这个文件夹下的所有测试文件

  • 使用 pytest 测试当前文件夹下的所有测试文件

  • 格式

    • 文件名 test_<something>.py 或者 <something>_test.py
    • 方法或者函数名 test_<something>
    • 类名 Test<Something>
  • pytest 的输出

    • PASSED (.) 成功
    • FAILED (F) 失败
    • SKIPPED (s) 跳过 需要使用装饰器 @pytest.mark.skip 或者
      @pytest.mark.ifskip()
    • xfail (x) 使用装饰器 @pytest.mark.xfail() 如果测试失败显示 xfail
      如果成功就是 XPASS(X).
    • XPASS (X) 不去跳过 pass, ran, passed
    • ERROR (E) 错误
  • 测试一个测试文件中的一个测试例 pytest test_something.py::test_nihao

命令行参数

  • 使用 pytest -v 选项显示详细的信息
  • --collect-only 只进行收集所有的测试例
  • -k 匹配测试例 匹配字符串用 'or' 分割 pytest "asdict or defaults"
  • -m 只测试某些有特殊标记的测试例
    import pytest
    
    ...
    @pytest.mark.你好
    def test_member_access():
    ...
    使用 pytest -m 你好 去测试
  • -x 遇到失败立刻退出
  • --tb=no 不显示错误信息,还有其他的一些参数
  • --maxfail
  • –-lf, -–last-failed
  • –ff, –failed-first
  • -q 静默模式
  • -l
  • -s 输出测试文件中的print

  • 捕获异常
    def xxx():
        raise TypeError
    with pytest.raises(TypeError):
        xxx()

  • 给测试函数打标记然后 通过 -m 参数去筛选出我们想要测试的测试函
    import pytest
    
    @pytest.mark.user
    @pytest.mark.role
    def xxx():
        pass
    
    @pytest.mark.user
    @pytest.mark.roles
    def yyy():
        pass
    -m 的筛选字符串可以写成下面的样子:
        "user"
        "user or roles"
        "user and role"
        "user and not role"

  • 添加上下文,比如连接数据库等
    import pytest
    
    @pytest.fixture(autouse=True)
    def xxx(tmpdir):
        print(tmpdir)
        yield
        print("结束")
    
    def test_xx():
        print("开始")
  • 跳过测试用例
    通过 -rs 参数可以输出reason
    import pytest
    
    x = 200
    
    @pytest.mark.skip(reason="我就是想要跳过这个测试")
    def test_xxx():
        assert None is None
    
    @pytest.mark.skipif(x != 100,reason="x 不等于100所以跳过")
    def test_yyy():
        assert None is None
    除了 -rs 还有 -rp 等等
    (f)ailed, (E)error, (s)skipped, (x)failed, (X)passed,
    (p)passed, (P)passed with output, (a)all except pP.
  • 当我们预期到可能存在错误时可以使用 xfail 标记
    import pytest
    
    x = 100
    
    @pytest.mark.xfail(x == 100,reason="x 等于 100")
    def test_xxx():
        assert None is not None
    
    @pytest.mark.xfail()
    def test_yyy():
        assert None is None
    
    @pytest.mark.xfail(reason="我预期到这里要失败")
    def test_zzz():
        assert None is not None

  • 测试单个实例 pytest -v tests/func/test_api_exceptions.py::TestUpdate::test_bad_id, 单个文件,文件夹,类都照着这个写.

  • 多次测试不同的函数,但是每一次有不同的参数
    import pytest
    
    @pytest.mark.parametrize("a,b,c", [(1,2,3),(4,5,6)])
    def test_xxx(a,b,c):
        assert a in range(100) and b in range(100) and c in range(100)

pytest Fixtures

  • fixture 简单用
    import pytest
    
    @pytest.fixture()
    def some_data():
        return 42
    def test_some_data(some_data):
        assert some_data == 42
  • 通过 conftest.py 共享 fixture. 通常情况下将 conftest.py 放到
    测试文件夹的根目录,当然其他子目录也可以,但是根目录会更加的有意义. pytest
    会自动的找 这个文件所以不用在测试文件中导入这个模块
  • 用 fixture 配置 Setup 和 Teardown
    import pytest
    
    class Data:
        def b(self):
            print("开始")
            print(self)
        def e(self):
            print("结束")
            print(self)
    d = Data()
    
    @pytest.fixture()
    def tasks_db():
        d.b()
        yield
        d.e()
    
    def test_xxx(tasks_db):
        print("开始测试")
    
    def test_yyy(tasks_db):
        print("开始测试了")
  • 指定 fixture 的范围
    import pytest
    
    @pytest.fixture()
    def data_1():
        return (1, 2, 3)
    
    @pytest.fixture()
    def data_2():
        return (4, 5, 6)
    
    
    @pytest.fixture(scope="session")
    def data_3():
        print("开始3")
        yield "你好"
        print("结束3")
    
    
    @pytest.fixture(scope="session")
    def data_4():
        print("开始4")
        yield
        print("结束4")
    
    
    def test_xxx(data_1, data_2, data_3, data_4):
        print(data_1)
        print(data_2)
        print(data_3)
    
    def test_yyy(data_1, data_2, data_3, data_4):
        print(data_1)
        print(data_2)
        print(data_3)
    
    范围一共有 function, class, module, session.
    表示的是 在什么范围内只运行一次.
  • 类使用 fixture
    import pytest
    
    @pytest.fixture(scope='class')
    def class_scope():
        """A class scope fixture."""
        print("你好")
        yield
        print("结束")
    
    @pytest.mark.usefixtures('class_scope')
    class TestSomething():
        """Demo class scope fixtures."""
    
        def test_1(self):
            """Test using a class scope fixture."""
        def test_2(self):
            """Again, multiple tests are more fun."""
  • 习惯上总是使用 autouse
    """Demonstrate autouse fixtures."""
    
    import pytest
    import time
    
    
    @pytest.fixture(autouse=True, scope='session')
    def footer_session_scope():
        """Report the time at the end of a session."""
        yield
        now = time.time()
        print('--')
        print('finished : {}'.format(time.strftime('%d %b %X', time.localtime(now))))
        print('-----------------')
    
    
    @pytest.fixture(autouse=True)
    def footer_function_scope():
        """Report test durations after each function."""
        start = time.time()
        yield
        stop = time.time()
        delta = stop - start
        print('\ntest duration : {:0.3} seconds'.format(delta))
    
    def test_1():
        """Simulate long-ish running test."""
        time.sleep(1)
    
    
    def test_2():
        """Simulate slightly longer test."""
        time.sleep(1.23)
    
    可以使用 autouse=True 来使 这个 fixture 被自动的使用,和直接写相比,不能够传入参数了.
    如果这样写十分的有必要不然的话,建议是直接写名字
  • 重命名 fixture
    通常情况下我们使用函数名当作 fixture 的名字,也可是使用 @pytest.fixture(name="lue") 这样来指定 fixture 的名字.
  • fixture 参数
    import pytest
    
    datas = ((1, 2, 3), (4, 5, 6), (7, 8, 9))
    data_ids = ["test_1","test_2","test_3"]
    
    @pytest.fixture(params=datas, ids=data_ids)
    def f_a(request):
        return request.param
    
    def test_a(f_a):
        print(f_a)
    
    解释一下这里的 ids 就是为了我们测试的时候知道显示出来的字符串,就是为了看起来方便.
    ids 可以是一个函数,函数的参数,就是 datas 中的一项
    可以在 f_a 中添加对数据的处理.
@copie copie added the pytest label Oct 25, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant