pytestの簡単な勉強
36879 ワード
pytestの簡単な勉強
一、紹介とダウンロードインストール
pip install -U pytest
py.test --version
またはpytest --version
二、基礎ユニットテスト(assert断言)
# example
>>>assert 1 == 1
>>>assert 2+2 == 2*2
>>>assert len('hello') < 10
>>>assert len('hello') > 10
Traceback (most recent call last):
File "" , line 1, in
AssertionError
>>>assert len('hello') > 10, ' 10'
Traceback (most recent call last):
File "" , line 1, in
AssertionError: 10
>>>assert range(4) == [0,1,2,3]
上記のassertの例から,ユニットテストに適していることがわかる.
1、テスト関数の例
def func(x):
return x+1
def test_func():
assert func(3) == 5
端末に入り、そのファイルが存在するディレクトリの下で
pytest
を実行する.実行結果は次のとおりです.========================= test session starts =========================
platform linux2 -- Python 2.7.13+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1
rootdir: /home/light/code/study/test_pytest, inifile:
plugins: celery-4.2.1
collected 1 item
test_pytest.py F [100%]
========================= FAILURES =========================
_________________________ test_func ________________________
def test_func():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_pytest.py:6: AssertionError
========================= 1 failed in 0.39 seconds =========================
pytestは現在のディレクトリの下で、testで始まるファイル(つまりテストファイル)を探し、テストファイルを見つけたら、テストファイルに入ってtest_を探します.最初のテスト関数を実行します.上記のテスト出力により、このテスト中にテスト関数が収集され、テスト結果が失敗(Fとマークされている)し、FAILURES部分に詳細なエラー情報が出力され、テストの原因を分析するのに役立ち、「assert func(3)==5」という文がエラーになりました.エラーの原因はfunc(3)=4です.
2、テストクラスの例
class TestClass:
def test_one(self):
x = "this"
assert 'h' in x
def test_two(self):
x = "hello"
assert hasattr(x, 'check')
端末に入り、そのファイルが存在するディレクトリの下で
pytest
を実行する.実行結果は次のとおりです.========================= test session starts =========================
platform linux2 -- Python 2.7.13+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1
rootdir: /home/light/code/study/test_pytest, inifile:
plugins: celery-4.2.1
collected 3 items
test_pytest.py ..F [100%]
========================= FAILURES =========================
________________________ TestClass.test_three ________________________
self = 0x7f9371aa09d0>
def test_three(self):
x = 'world'
> assert hasattr(x, 'hello')
E AssertionError: assert False
E + where False = hasattr('world', 'hello')
test_pytest.py:20: AssertionError
========================= 1 failed, 2 passed in 0.14 seconds =========================
pytestは現在のディレクトリの下で、testで始まるファイル(すなわちテストファイル)を探し、テストファイルを見つけた後、テストファイルに入ってTestで始まるテストクラスを探して実行します.上記のテスト結果を見ると、3つのテスト関数が採集されていることがわかります.そのうち、最初の2つは成功(.表示)、最後の1つは失敗(F表示)、FAILURES部分を見ると、False=hasattr(‘world’,‘hello’)、つまり‘world’に‘hello’属性がないので、エラーが表示されます.
3、テストサンプルの作成方法
前の2つの例を通して、いくつかの法則を見ることができます.-一般的には、テストファイルがあるフォルダでpytestを実行するだけでテストを開始できます.テストファイルはtest_先頭または_test末尾-test_で関数をテスト先頭-テストクラスはTestで始まり、__はありません.init__メソッド-assertの使用を断言-以上の条件を満たすとpytestは直接テスト例を実行できます.
三、fixture方法
def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
1、fixture簡単な例
import pytest
@pytest.fixture()
def before():
print '
before each test'
def test_1(before):
print 'test_1()'
def test_2(before):
print 'test_2()'
assert 0
上のコードはfixtureメソッドでbefore関数を装飾し、before関数は1行のデータを印刷します.2つのテスト関数のパラメータにbeforeがあります.
端末に入り、そのファイルが存在するディレクトリの下で
pytest -v -s
を実行する.(備考:-vは結果.PASEDにマッピングし、FをFAILEDにマッピングする、-sはコードプロセスを実行することを指す)========================= test session starts =========================
platform linux2 -- Python 2.7.13+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1 -- /home/light/.virtualenvs/study/bin/python2.7
cachedir: .pytest_cache
rootdir: /home/light/code/study/test_pytest, inifile:
plugins: celery-4.2.1
collected 2 items
test_pytest.py::test_1
before each test
test_1()
PASSED
test_pytest.py::test_2
before each test
test_2()
FAILED
========================= FAILURES =========================
________________________ test_2 ________________________
before = None
def test_2(before):
print 'test_2()'
> assert 0
E assert 0
test_pytest.py:15: AssertionError
========================= 1 failed, 1 passed in 0.03 seconds =========================
結果から、2つのテスト関数が実行前に1行のデータを印刷していることがわかります.この例は意味がないかもしれませんが、before関数がファイルを開いたりsessionを開いたりすると、テスト関数が直接使用できます.
2、3種類の呼び出しfixture方式
テスト関数の直接呼び出し
markを通るusefixtures()呼び出し
import pytest
@pytest.fixture()
def before():
print('
before each test')
@pytest.mark.usefixtures("before")
def test_1():
print('test_1()')
@pytest.mark.usefixtures("before")
def test_2():
print('test_2()')
class Test1:
@pytest.mark.usefixtures("before")
def test_3(self):
print('test_1()')
@pytest.mark.usefixtures("before")
def test_4(self):
print('test_2()')
@pytest.mark.usefixtures("before")
class Test2:
def test_5(self):
print('test_1()')
def test_6(self):
print('test_2()')
Autouseで呼び出す
import time
import pytest
@pytest.fixture(scope="module", autouse=True)
def mod_header(request):
print('
-----------------')
print('module : %s' % request.module.__name__)
print('-----------------')
@pytest.fixture(scope="function", autouse=True)
def func_header(request):
print('
-----------------')
print('function : %s' % request.function.__name__)
print('time : %s' % time.asctime())
print('-----------------')
def test_one():
print('in test_one()')
def test_two():
print('in test_two()')
Autouseは直訳して自動的に呼び出され、scopeと協力する必要があります.-fixtureメソッドプロトタイプ:
def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
scopeは範囲を表し、autouseは自動呼び出しの有無を表します.-scope function: test , function scope
class: class test
module: module test
session: session , session pytest ,
3、fixture戻り値
上記の例では、fixtureの戻り値はデフォルトNoneであり、fixtureに必要なものを返すように選択することができます.fixtureでデータを構成したり、ファイルを読んだり、データベースに接続したりする必要がある場合は、fixtureにこれらのデータやリソースを返すことができます.
パラメータfixtureをどのように持つかはパラメータも持つことができ、パラメータをparamsに割り当てることができ、デフォルトはNoneです.paramの各値についてfixtureは実行を呼び出し、forループを実行するようにparamsの値を1回遍歴します.test_fixture_param.py
import pytest
@pytest.fixture(params=[1, 2, 3])
def test_data(request):
return request.param
def test_not_2(test_data):
print('test_data: %s' % test_data)
assert test_data != 2
========================= test session starts =========================
platform linux2 -- Python 2.7.13+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1 -- /home/light/.virtualenvs/study/bin/python2.7
cachedir: .pytest_cache
rootdir: /home/light/code/study/test_pytest, inifile:
plugins: celery-4.2.1
collected 3 items
test_param.py::test_not_2[1] test_data: 1
PASSED
test_param.py::test_not_2[2] test_data: 2
FAILED
test_param.py::test_not_2[3] test_data: 3
PASSED
========================= FAILURES =========================
3つのパラメータがそれぞれ実行されていることがわかります.
4、テストデータベース接続の例
# -*-coding:utf-8 -*-
#
# Models.py
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
Base = declarative_base()
class User(Base):
__tablename__ = 'User'
id = Column('id', Integer, primary_key=True, autoincrement=True)
name = Column('name', String(50), unique=True)
age = Column('age', Integer)
def __repr__(self):
return "" % (
self.id, self.name, self.age)
class Role(Base):
__tablename__ = 'Role'
id = Column('id', Integer, primary_key=True, autoincrement=True)
name = Column('name', String(50), unique=True)
def __repr__(self):
return "" % (self.id, self.name)
# -*-coding:utf-8 -*-
# fixture ,
# -*- coding:utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from Models import Base, User, Role
import pytest
@pytest.fixture(scope='module', autouse=True)
def connect():
"""
, session
pytest
"""
print('conn...')
conn_str = 'mysql+mysqlconnector://root:password@localhost:3306/pytest'
engine = create_engine(conn_str, echo=True)
db_session = sessionmaker(bind=engine)
Base.metadata.create_all(engine)
session = db_session()
return session
@pytest.fixture(scope='function', autouse=True)
def start_test():
print('
start test...')
def test_delete_data(connect):
""" fixture"""
session = connect
session.query(User).delete()
session.query(Role).delete()
assert session.query(User).all() == []
assert session.query(Role).all() == []
def test_add_data(connect):
u1 = User(name='Light', age=2)
u2 = User(name='Ash', age=20)
r = Role(name='user')
session = connect
session.add(u1)
session.add(u2)
session.add(r)
session.commit()
assert session.query(User).all() != []
assert session.query(Role).all() != []
def test_select_data(connect):
session = connect
data1 = session.query(User).filter(User.id == '1').first()
data2 = session.query(User).filter(User.id == '2').first()
data3 = session.query(Role).filter(Role.id == '1').first()
assert data1.name == 'Light' and data1.age == 23
assert data2.name == 'Ash' and data2.age == 20
assert data3.name == 'user'
def test_drop_table(connect):
session = connect
session.execute("drop table User")
session.execute("drop table Role")
assert session.execute('show tables').rowcount == 0
上のコードに注意して、fixtureはmoduleレベルのautouse=Trueを使用しています.実行した結果、最初のテストをしたときだけデータベースに接続され、その後データベースに接続されていないことがわかります.
端末対応フォルダに入りpytest-v test_を実行session.py
========================= test session starts =========================
platform linux2 -- Python 2.7.13+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1 -- /home/light/.virtualenvs/study/bin/python2.7
cachedir: .pytest_cache
rootdir: /home/light/code/study/test_pytest, inifile:
plugins: celery-4.2.1
collected 4 items
test_session.py::test_delete_data PASSED [ 25%]
test_session.py::test_add_data PASSED [ 50%]
test_session.py::test_select_data PASSED [ 75%]
test_session.py::test_drop_table PASSED [ 100%]
========================= 4 passed in 1.06 seconds =========================
5、テストファイルの書き込み例
import pytest
@pytest.fixture(scope='module', autouse=True)
def openfile():
print('open the file...')
f = open('test.txt', 'a')
return f
def test_write1(openfile):
f = openfile
old_tell = f.tell()
data = '1111111111
'
f.write(data)
new_tell = f.tell()
assert new_tell - old_tell == len(data)
def test_write2(openfile):
f = openfile
old_tell = f.tell()
data = '2222222222
'
f.write(data)
new_tell = f.tell()
assert new_tell - old_tell == len(data)
def test_close(openfile):
openfile.close()
with pytest.raises(ValueError) as e:
openfile.write('3')
pytest -v -s test_file.py
=========================================== test session starts ===========================================
platform linux2 -- Python 2.7.13+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1 -- /home/light/.virtualenvs/study/bin/python2.7
cachedir: .pytest_cache
rootdir: /home/light/code/study/test_pytest, inifile:
plugins: celery-4.2.1
collected 3 items
test_file.py::test_write1 open the file...
PASSED
test_file.py::test_write2 PASSED
test_file.py::test_close PASSED
======================================== 3 passed in 0.07 seconds =========================================
ファイルが一度だけ開いているのが見えます.
四、mark類
1、簡単な-m
import pytest
@pytest.mark.a
def test_a_1():
print('this is a')
@pytest.mark.a
def test_a_2():
print('this is a')
@pytest.mark.b
def test_b_1():
print('this is b')
上のコードには、それぞれ2つのaテスト、1つのbテストが表示されています.
`pytest -v test_mark1.py -m a`
...
collected 3 items / 1 deselected
test_mark1.py::test_a_1 PASSED [ 50%]
test_mark1.py::test_a_2 PASSED [100%]
...
`pytest -v test_,ark1.py -m b`
...
collected 3 items / 2 deselected
test_mark1.py::test_b_1 PASSED [100%]
...
-mの後に指定した文字がタグに対応してテスト関数を実行することがわかります.
`pytest -v test_mark1.py -m "not a"`
...
collected 3 items / 2 deselected
test_mark1.py::test_b_1 PASSED [100%]
...
`pytest -v test_mark1.py -m "not b"`
...
collected 3 items / 1 deselected
test_mark1.py::test_a_1 PASSED [ 50%]
test_mark1.py::test_a_2 PASSED [100%]
...
`pytest -v test_mark1.py -m "a or b"`
...
collected 3 items
test_mark1.py::test_a_1 PASSED [ 33%]
test_mark1.py::test_a_2 PASSED [ 66%]
test_mark1.py::test_b_1 PASSED [100%]
...
`pytest -v test_mark1.py -m "a and b"`
...
collected 3 items / 3 deselected
...
上記のコマンドライン実行後の結果からpytest-mの後のパラメータが論理的に判断できることがわかる(not,and,or).これは重要です.-kもそうですから.
2、一意ID実行
テスト関数を1つだけ実行したいと仮定し、それ以外は実行しない場合は、コマンドラインで指定できます.
pytest -v test_mark1.py::test_a_1
`pytest -v test_mark1.py::test_a_1`
...
collected 1 item
test_mark1.py::test_a_1 PASSED [100%]
...
3、簡単な-k
kはkeyword,テスト関数のキーワードを指す.markタグテスト関数を使用しないと仮定すると、-kで直接テストしたい関数の名前または一部の名前を指定することもできます.
`pytest -v test_mark1.py -k a_`
...
collected 3 items / 1 deselected
test_mark1.py::test_a_1 PASSED [ 50%]
test_mark1.py::test_a_2 PASSED [100%]
...
`pytest -v test_mark1.py -k "a_ or b_"`
...
collected 3 items
test_mark1.py::test_a_1 PASSED [ 33%]
test_mark1.py::test_a_2 PASSED [ 66%]
test_mark1.py::test_b_1 PASSED [100%]
...
`pytest -v test_mark1.py -k "not a_"`
...
collected 3 items / 2 deselected
test_mark1.py::test_b_1 PASSED [100%]
...
−mの使用を理解し,−kのパラメータも論理的に判断できる.