Pytest Book CHAPTER 2, Writing Test Functions
- Expecting Exceptions
- Marking Test Functions
- Skipping Tests
- Marking Tests as Expecting to Fail
- Parametrized Testing
Expecting Exceptions
- Make sure a function (especially API function) raises expected exception.
- Always raise exception from API function if desirable type is not passed.
- Simple check for type of exception raised example.
def test_add_raises(): """add() should raise an exception with wrong type param.""" with pytest.raises(TypeError): tasks.add(task='not a Task object')- Non
Taskobject is added to tasks list.addmethod should raiseTypeErrorexception
- Non
- Sometime we may need to check for exception parameters.
- This let us look at exception more closely.
def test_start_tasks_db_raises(): """Make sure unsupported db raises an exception.""" 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'"- Not only db_type should be
str(passedmysqldb_type), it should be eithertinyormongo.
- Not only db_type should be
Marking Test Functions
- pytest provides a cool mechanism to let us mark the test functions
- Useful for marking subset of our tests as “smoke test”.
- Smoke test let us get a sense for whether or not there is some major break in the system. It’s by convention not all-inclusive of tests.
-
Smoke test let us get a sense for whether or not there is some major break in the system. It’s by convention not all-inclusive of tests.
@pytest.mark.smoke def test_list_raises(): """list() should raise an exception with wrong type param.""" with pytest.raises(TypeError): tasks.list_tasks(owner=123) @pytest.mark.get @pytest.mark.smoke def test_get_raises(): """get() should raise an exception with wrong type param.""" with pytest.raises(TypeError): tasks.get(task_id='123') - Run the smoke test with
-moption$ pytest -m "smoke" test_api_exceptions.py $ pytest -v -m 'smoke and not get' test_api_exceptions.py
Skipping Tests
- Pytest has a few helpful builtin markers like
skipandskipiffor skipping the test - We can use it to skip test that we don’t want to run.
@pytest.mark.skip(reason='misunderstood the API') def test_unique_id_1(): """Calling unique_id() twice should return different numbers.""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2 - Sometime we skip the test unless some conditions are met.
@pytest.mark.skipif(tasks.__version__ < '0.2.0', #expression can be any valid python expression reason='not supported until version 0.2.0') def test_unique_id_1(): """Calling unique_id() twice should return different numbers.""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2 - Include reason of skip of the test. We can see the reason for skipping of test with
-rsflag.$ pytest -rs test_unique_id_3.py
Marking Tests as Expecting to Fail
- Use
xfailbuiltin marker to mark test to run but it’s expected to fail. - In the report,
xis forXFAIL, meaning “expected to fail”,Xis forXPASS, meaning “expected to fail but passed” - We can configure pytest to report the tests that pass but were marked with
xfailas FAIL. Just add this in pytest.ini file:[pytest] xfail_strict=true
Parametrized Testing
- It is a way to test a test function with multiple sets of test data (corner cases).
@pytest.mark.parametrize('task', [Task('sleep', done=True), Task('wake', 'brian'), Task('breathe', 'BRIAN', True), Task('exercise', 'BrIaN', False)]) def test_add_2(task): """Demonstrate parametrize with one parameter.""" task_id = tasks.add(task) t_from_db = tasks.get(task_id) assert equivalent(t_from_db, task)