Read Python Testing with pytest: Simple, Rapid, Effective, and Scalable to learn Python and testing framework for it.
I am new for Python, but I need to maintain some python libraries in order to keep it up to date. Thus, I started learning Python and its world.
Thus, I took the Python testing book. Below is a note about it for me.
Mark feature
In pytest, we can mark each test as @pytest.mark.smoke, for example. We can run only marked tests as:
$ pytest -m smoke runable/test/path.py
The mark is settable multiply. We can specify multiple marks like below.
@pytest.mark.one
@pytest.mark.two
def test_one_and_two_tests():
....
setup and teardown
Inunittest, we can use setUp/tearDown to set test data.
In pytest, we can define them like below. yield is an important part to call setup/teardown
@pytest.fixture(autouse=True)
def initialized_tasks_db (tmpdir):
# Setup : start db
tasks.start_tasks_db(str(tmpdir), 'tiny' )
yield # this is where the testing happens
# Teardown : stop db
tasks.stop_tasks_db()
Skip
We can skip test cases with reasons by skipif.
@pytest.mark.skipif(tasks.__version__ < '0.2.0' , reason= 'not supported until version 0.2.0' )
def test_unique_id_1 ():
id_1 = tasks.unique_id()
id_2 = tasks.unique_id()
assert id_1 != id_2
We can also use skip and xfail in addition.
Raise
We can test raising errors like below.
def test_start_tasks_db_raises ():
with pytest.raises(ValueError) as excinfo:
tasks.start_tasks_db( 'some/great/path' , 'mysql' )
exception_msg = excinfo.value.args[0]
assert exception_msg == "db_type must be a 'tiny' or 'mongo'"
with syntax is very helpful in Python, ah…
ParamrizedTest
number_pairs = (
('one', 'one'),
('two', 'two'),
('three','there')
)
@pytest.mark.parametrize('numbers', number_pairs)
def test_numbers(self, numbers):
(former, later) = numbers
assert former == later
Easy to read. We can understand where we failed. nice.
_____________________________________________________________________________ TestWebDriverWebDriver.test_numbers[numbers2] ______________________________________________________________________________
self = <webdriver_test.TestWebDriverWebDriver object at 0x102c3a588>, numbers = ('three', 'there')
@pytest.mark.parametrize('numbers', number_pairs)
def test_numbers(self, numbers):
(former, later) = numbers
> assert former == later
E AssertionError: assert 'three' == 'there'
E - three
E ? -
E + there
E ? +
test/unit/webdriver/webdriver_test.py:96: AssertionError
======================================================================================== short test summary info =========================================================================================
FAIL test/unit/webdriver/webdriver_test.py::TestWebDriverWebDriver::()::test_numbers[numbers2]
1 failed, 9 passed in 0.61 seconds
About tests/conftest.py
Although conftest.py is a Python module, it should not be imported by test files. Don’t import conftest from anywhere. The conftest.py file gets read by pytest, and is considered a local plugin , which will make sense once we start talking about plugins in Chapter 5, Plugins . For now, think of `tests/conftest.py` as a place where we can put fixtures used by all tests under the tests directory.
Fixture
A name of methods which has a fixture annotation can be used an argument for another test_ method. If the name matches each other, the fixture becomes one argument for the test method. We can use multiple fixtures like the same way.
@pytest.fixture()
def tuple_fixture():
return (1, 'neko', None, { 'inu': 23 })
def test_tuple_fixture(tuple_fixture):
assert tuple_fixture[3]['inu'] != 32
assert tuple_fixture[2] is None
A fixture can be an argument as another fixture. The same fixture can be a test method like nested relation. Fixture feature has a scope. It has function, class, module and session. The default value is function.
We can specify them using usefixtures.
@pytest.fixture(scope='class')
def class_coped_fixture1():
return 'one example'
# ...
@pytest.mark.usefixtures('class_coped_fixture1', 'class_coped_fixture2')
class TestSomething(object):
def test_1(self, class_coped_fixture1, class_coped_fixture2):
"""Can use 'class_coped_fixture1' and 'class_coped_fixture2'"""
def test_2(self, class_coped_fixture1, class_coped_fixture2):
"""Can use 'class_coped_fixture1' and 'class_coped_fixture2' again"""
Of course, we can the fixture in Parametrized test.
Interesting build-in fixtures are available like below.
available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factor
Plugin and toolchains, configurations
The book also addressed plugin feature for pytest. A tool, named tox, was also explained.
We can define configurations for pytest using pytest.ini file for example.
Is this style common in Python world? ah…
Wrap up
Through the book, I learned Python world and pytest. Personally, learning test framework in the language is important since if it is necessary to implement something in the language. I already had a little Python knowledge such as syntax, so I was able to learn smoothly.
1 Comment