pytest æäœéå ¥é
pytestã®äœ¿ãæ¹ãæ¯åå¿ããŠããŸãã®ã§ããã䜿ã颿°ãæ©èœã»ã©ã€ãã©ãªããŸãšããŠããã
ä»åŸããŸãå¿ããæã«ãã®ããŒãžãèŠè¿ãããšã«ããã
åºæ¬äžã®åºæ¬
assert
pytestã®åºæ¬äžã®åºæ¬ããã®é¢æ°ã§çµæã®æ€èšŒãè¡ãã
æ€èšŒããã³ãŒããTrueãè¿ããªããã¹ãæåãFalseãè¿ããªããã¹ã倱æã«ããã
å人çã«ã¯ãããã ãã§ãã¹ãã§ããã·ã³ãã«ãã奜ãã
ãã¹ãã©ã€ãã©ãªã«ããããassertEqualsã®ãããªæ€èšŒé¢æ°ã沢山ããã®ã¯èŠæã
def test_ok():
actual = 2
assert actual == 2
def test_fail():
actual = 2
assert actual == 1
pytest.raises
ãããpytestã®åºæ¬äžã®åºæ¬ãç®æ°ã§èšãåŒãç®ãããã®åºæ¬ã
äŸå€ãçºçãããã®ãã§ãã¯ãè¡ãã
ãã®ãããã¯ã®äžã§äŸå€ãçºçããããã¹ãæåãçºçããªããã°ãã¹ã倱æã
def test_error():
# çºçããŠã»ããErrorã¯ã©ã¹ãraisesã«åŒæ°ãšããŠäžãã
with pytest.raises(ValueError):
# äŸå€ãçºçãã颿°å®è¡
func_raise_error()
絶察èŠéããªãäŸ¿å©æ©èœïŒãã¹ãã³ãŒãã®ççž®åã»ä¿å®æ§åäž
pytest.mark
åºæ¬ïŒãã¹ãã®ã«ããŽã©ã€ãºæ©èœ
@pytest.mark.databaseãªã©ãšãã¹ãã±ãŒã¹ã«ä»äžãããšãã«ããŽãªå¥ã«ãã¹ãå®è¡ããããšãå¯èœã«ãªã
以äžã®ãã¹ãã³ãŒããããç¶æ
ã§ãpytest -m databaseãšCLIããå®è¡ãããšã@mark.databaseãšãã³ã¬ãŒããããŠããã®ããå®è¡ãããªããªãã
@pytest.mark.database
def test_database_access():
assert ...
@pytest.mark.no_database
def test_print():
assert ...
pytest.mark.parameterize
ãåããããªãã¹ããããã©ãããŒã¿ã ãéã...ãã¹ãã³ãŒãã倪ã...ããŠããç¶æ³ã解決ããŠãããã
åããã¹ãã³ãŒãã«å¯ŸããŠã䌌ããããªããŒã¿ã1ã€ã®ã±ãŒã¹ã§ãã¹ãã§ããã
ãã¹ãã®ä¿å®æ§åäžã»å¯èªæ§åäžã«ã€ãªããã
ã @pytest.mark.parametrize("data1,data2", [
ã (1, "a"),
ã (2, "b")
ã ])
ã def test_sample(data1, data2):
ã assert sut(data1, data2) == True
pytest.fixture
æ§ã ãªãã¹ãå ±éã§å©çšããåŠçããŸãšããããäºååŠçãäºåŸåŠçãªãããåãæãŠãã
åºæ¬äžã®åºæ¬
@pytest.fixtureã§å®çŸ©ãã颿°ã®ååãããã¹ãã±ãŒã¹ã®åŒæ°ã«äžããŠå©çšããã
ãããassertã®æãšäžç·ã§èªç±åºŠãé«ãã
fixture颿°ã§æ§ã
ãªåŠçããã¹ãã±ãŒã¹ããåé¢ã§ããã
@pytest.fixture
def readable_file():
with open("test_file.txt") as f:
return f
def test_read_file(readable_file):
assert readable_file.read() == '...'
äºåŸåŠçã®ããæ¹
çãã¯æ±ºãŸã£ãŠããŠãyieldã䜿ãã°ããã
ãã¹ãåã¯yieldãŸã§ã®åŠçãå®è¡ããããã¹ãåŸã«yield以éã®åŠçãå®è¡ãããã
@pytest.fixture
def readable_file():
f = open("test_file.txt")
yield f
f.close()
def test_read_file(readable_file):
assert readable_file.read() == '...'
åŒæ°ãäžããæ¹æ³
ã©ãããå©çšããŠåŒæ°ä»ãã®é¢æ°ãè¿ãããã«ããã°ããã
@pytest.fixture
def readable_file():
def inner(path):
with open(path) as f:
return f
return inner
def test_read_file(readable_file):
assert reaable_file("test_file.txt").read() == '...'
å šãã¹ãå ±éã®åŠçãå®çŸ©ããããªã
testsãã£ã¬ã¯ããªã®é
äžã«conftest.pyãäœæããããã«fixture颿°ãèšèŒããã°ããã
conftest.pyã«fixtureãå®çŸ©ããã°ãæ§ã
ãªãã¹ãã³ãŒãããå©çšå¯èœã«ãªãã
# conftest.pyã«readable_fileãå®çŸ©ããŠãç¶æ
# åããã¡ã€ã«ã«fixture颿°ãå®çŸ©ããŠãªããŠãå©çšå¯èœãconftest.pyããåç
§ããŠãã
def test_read_file(readable_file):
assert reaable_file("test_file.txt").read() == '...'
åŒæ°ã«äžãããšããèªåã§å®æœãããã
autouse=Trueãå©çšããã°ããã
ãã¹ãã±ãŒã¹ã«ããããåŒæ°ãäžãããšãã圱é¿ããå
šãã¹ãã±ãŒã¹ã®å®è¡åã«åŠçãèµ°ãã
@pytest.fixture(autouse=True)
def all_test_config():
print('all use')
䟿å©ã©ã€ãã©ãª
pytest-describeïŒRspec(ruby)ã®ããã«ãã¹ãã³ãŒããéå±€æ§é ã§æžãã
pip install pytest-describeã§ã€ã³ã¹ããŒã«å¯èœã
describe_*ãšããååã§é¢æ°ãæžãã°ãæ°žé ã«éå±€æ§é ã«ã§ããã
describe_*é
äžã«ããããã以å€ã®é¢æ°ã¯ãã¹ãã±ãŒã¹ãšããŠæ±ãããã
def describe_parent():
def describe_child():
def it_test():
assert ...
def describe_grandchild():
def it_grand_test():
assert ...
def describe_child2():
def it_test():
assert ...
pytest-mockïŒã¢ã㯠ã©ã€ãã©ãª
ã¢ãã¯ãç°¡åã«äœãåºããã©ã€ãã©ãªãå¿
èŠãªãæ¬ã³ãŒãã®äžéšãã¢ãã¯åããããšãå¯èœ
mockãå©çšããã«ããã£ãŠãæäœéèŠããŠãããšäŸ¿å©ãªããšã ãèšèŒããŠãã
æºå
1.pytest-mockãã€ã³ã¹ããŒã«ãã
pip install pytest-mock
2.ãã¹ãã±ãŒã¹ã®åŒæ°ã«mockerãäžããïŒfixtureã®å¿çšïŒ
def test_sample(mocker):
...
3.mockerãå©çšããŠè²ã
ã¢ãã¯åãã
def test_sample(mocker):
mocker.patch("src.sample.add", return_value=2)
...
äŸ¿å©æ©èœ1ïŒmocker.Mock -- ããããªåœ¢ã®ã¢ãã¯ãäœã --
ãªãããããMockã䜿ãã®ãïŒ
äŸãã°ãèªåã§SampleMockã®ãããªã¯ã©ã¹ãäœã£ãŠå®è£
ããã°ããã®ã§ã¯ïŒ
A. èªåã§äœãã®ã¯é¢åèã + Mockã®äŸ¿å©é¢æ°ãå©çšã§ãã
- æµç³ã«èªåã§Mockãäœãã®ã¯é¢åèããããã¹ãã³ãŒãã®å¯èªæ§ãäžæ°ã«èœã¡ã
- ãŸããMockã«ã¯ãäœååŒã³åºããããïŒããããããããªäŸ¿å©é¢æ°ãçšæãããŠã
åºæ¬â ïŒreturn_value -- mockãåŒåºãããæã®è¿ãå€ãèšå®ãã
>>> a = mocker.Mock(return_value='hoge')
>>> a()
'hoge'
åºæ¬â¡ïŒside_effect -- mockãåŒã³åºãããæã®é¢æ°ãã®ãã®ãäŸå€ãèšå®ãã
>>> m = mocker.Mock(side_effect=lambda: 'hoge')
>>> m()
'hoge'
>>> m = mocker.Mock(side_effect=Exception)
>>> m()
raise Exception(...)
åºæ¬â¢ïŒreturn_valueãside_effectã®äž¡æ¹èšå®ããå Žåãside_effectãåªå ããã
>>> a = mocker.Mock(return_value='hoge', side_effect=lambda: 'boge')
>>> a()
'boge'
å¿çšâ ïŒã¯ã©ã¹ã䌌ãããªããžã§ã¯ãäœæ
def test_sample(mocker):
m = mocker.Mock()
# ãmãã«prop_hogeããããã£ãèšå®ïŒå€ã¯1ïŒ
m.prop_hoge = 1
# ãmãã«func_hogeãšããã¡ãœãããèšå®ïŒè¿ãå€ã¯"aaaaaa"ïŒ
m.func_boge = mocker.Mock(return_value="aaaaaa")
# return_valueã«Mockãäžããã£ãŠã®ããå©çšããå Žé¢ãã
return_mock = mocker.Mock()
return_mock.banana = "ããã"
# ãmãã«return_mockãè¿ãã¢ãã¯é¢æ°ãèšå®
m.func_return_mock = mocker.Mock(return_value=return_mock)
ã€ã³ã¹ã¿ã³ã¹ã®ã¢ãã¯ãäœãæã®åºæ¬ã¯ããã ã
return_valueã«æŽã«ã¢ãã¯ãèšå®ããŠãããã
äŸ¿å©æ©èœ2ïŒmocker.MagicMock ---- Mockã®ãµãã¯ã©ã¹ãå©çšããå Žé¢ã¯å€ã
Mockãšæ©èœã¯ã»ãšãã©åãã
Mockãšã®éãã¯ãç¹æ®ã¡ãœãããããã©ã«ãã§å®è£
ããŠããã©ãããããã
åèïŒPython ãããã¢ãã¯ãã¹ã¿ãŒâ ïŒMockãªããžã§ã¯ãã®ãµããŸããæå®ããïŒ - Qiita
äŸ¿å©æ©èœ3ïŒmocker.patch ---- æ¬çªã³ãŒãã®é¢æ°ãã¯ã©ã¹ãã¢ãžã¥ãŒã«ãã¢ãã¯åã§ãããã°ããã€
ãã¹ããå®è¡ããæã ããæ¬çªã³ãŒãã®å
容ãå€ããããšãã§ãã
察象ãã¯ã©ã¹ãã¡ãœããã颿°ãã¢ãžã¥ãŒã«ã§ããªãã§ããã¢ãã¯åã§ããæ¬åœã«ãã°ããŠcoolãªãã€
åºæ¬çãªå
¥ãæ¿ãæ¹ãç¥ã£ãŠããã°ãããšã¯å€§äœå¿çšãå¹ã
颿°ãã¢ãã¯ãšå ¥ãæ¿ãã
def func1(name):
return f"hello!!{name}"
def func2(name):
return func1(name)
from sample import func2
def test_func2(mocker):
value = "no hello"
mocker.patch("src.sample.func1", return_value=value)
assert func2("...") == value
ã¯ã©ã¹äžžããšã¢ãã¯ãšå ¥ãæ¿ãã
def func1():
s = Sample()
return s.execute()
class Sample:
def execute(self):
return "execute"
from sample import Sample, func1
def test_func1(mocker):
text = "execute2!!"
m = mocker.Mock(spec=Sample)
m.execute.return_value = text
mocker.patch("src.sample.Sample", return_value=m)
assert func1() == text
importããŠãã¢ãžã¥ãŒã«ãã¢ãã¯ãšå ¥ãæ¿ãã¡ãã
import requests
def func1(url):
return func2(url)
def func2(url):
try:
return requests.get(url).status_code
except:
raise Exception()
from src.sample import func1
def test_sample(mocker):
status_code = 200
url = "http://hoge.com"
m = mocker.Mock()
m.status_code = status_code
mocker.patch("src.sample.requests.get", return_value=m)
assert func1(url) == status_code
äŸ¿å©æ©èœ4ïŒmocker.patch.object ---- çãæã«æãå±ãmocker.patchãå°ãå€ãããã€
mocker.patchãšåœ¹å²ã¯äžç·ãªã®ã ããå°ãäœ¿ãæ¹ãç°ãªã
ããã¹ã察象ãå©çšããŠãã¯ã©ã¹ã®äžéšã®ã¡ãœããã ãã¢ãã¯åãããããšãããå Žé¢ã§äœ¿ããã
äœ¿ãæ¹ã ãèŠãŠããã°ãããšã¯ããªã§è¡ããã¯ã
mocker.patchãšéãã®ã¯ãã¢ãžã¥ãŒã«ãã¢ãã¯åããããªãããã®ã¢ãžã¥ãŒã«ããã¹ããã¡ã€ã«ã§importããå¿
èŠããããšããç¹
以äžã¯requests.getãmocker.patch.objectã§ã¢ãã¯åãããã¿ãŒã³
import requests
def func1(url):
return func2(url)
def func2(url):
try:
return requests.get(url).status_code
except:
raise Exception()
import requests
from src.sample import func1
def test_sample(mocker):
status_code = 200
url = "http://hoge.com"
m = mocker.Mock()
m.status_code = status_code
mocker.patch.object(requests, "get", return_value=m)
assert func1(url) == status_code
Discussion
ãšãªãã¹ããšãããäœã«æã
ã«ãªã£ãŠãããšããããããŸããã(dãæããŠãã)
ãææããããšãããããŸããä¿®æ£ããŠãããŸããã