{"id":1590,"date":"2023-12-05T22:04:32","date_gmt":"2023-12-05T16:34:32","guid":{"rendered":"https:\/\/geekpython.in\/?p=1590"},"modified":"2024-03-01T17:04:02","modified_gmt":"2024-03-01T11:34:02","slug":"understanding-pytest-to-test-python-code","status":"publish","type":"post","link":"https:\/\/geekpython.in\/understanding-pytest-to-test-python-code","title":{"rendered":"How to Use Pytest &#8211; Fixtures, Parametrization, Markers, and more&#8230;"},"content":{"rendered":"\n<p>You may have done unit testing or heard the term unit test, which involves breaking down your code into smaller units and testing them to see if they are producing the correct output.<\/p>\n\n\n\n<p>Python has a robust unit testing library called <a href=\"https:\/\/geekpython.in\/unit-tests-in-python\" target=\"_blank\" rel=\"noreferrer noopener\">unittest<\/a> that provides a comprehensive set of testing features. However, some developers believe that <code>unittest<\/code> is more verbose than other testing frameworks.<\/p>\n\n\n\n<p>In this article, you&#8217;ll look at how to use the <code>pytest<\/code> library to create small, concise test cases for your code. Throughout the process, you&#8217;ll learn about the pytest library&#8217;s key features.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installation<\/h2>\n\n\n\n<p>Pytest is a third-party library that must be installed in your project environment. In your terminal window, type the following command.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">pip install pytest<\/pre><\/div>\n\n\n\n<p>Pytest has been installed in your project environment, and all of its functions and classes are now available for use.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Getting Started With Pytest<\/h2>\n\n\n\n<p>Before getting into what <code>pytest<\/code> can do, let&#8217;s take a look at how to use it to test the code.<\/p>\n\n\n\n<p>Here&#8217;s a Python file <code>test_square.py<\/code> that contains a <code>square<\/code> function and a test called <code>test_answer<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"test_square.py\"># test_square.py\n\ndef square(num):\n    return num**2\n\ndef test_answer():\n    assert square(3) == 10<\/pre><\/div>\n\n\n\n<p>To run the above test, simply enter the <code>pytest<\/code> command into your terminal, and the rest will be handled by the <code>pytest<\/code> library.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest\n========================================= test session starts ==========================================\nplatform win32 -- Python 3.10.5, pytest-7.3.2, pluggy-1.0.0\nrootdir: D:\\SACHIN\\Pycharm\\pytestt_lib\nplugins: anyio-3.6.2\ncollected 1 item\n\ntest_square.py F                                                                                  [100%]\n\n=============================================== FAILURES ===============================================\n_____________________________________________ test_answer ______________________________________________\n\n    def test_answer():\n&gt;       assert square(3) == 10\nE       assert 9 == 10\nE        +  where 9 = square(3)\n\ntest_square.py:7: AssertionError\n======================================= short test summary info ========================================\nFAILED test_square.py::test_answer - assert 9 == 10\n========================================== 1 failed in 0.27s ===========================================<\/pre><\/div>\n\n\n\n<p>The above test failed, as evidenced by the output generated by the <code>pytest<\/code> library. You might be wondering how <code>pytest<\/code> discovered and ran the test when no arguments were passed.<\/p>\n\n\n\n<p>This occurred because <code>pytest<\/code> uses standard test discovery. This includes the conventions that must be followed for testing to be successful.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>When no argument is specified, pytest searches files that are in <strong>*<em>_test.py<\/em><\/strong><em> <\/em>or<em> <strong>test_*.py<\/strong><\/em> format.<\/li>\n\n\n\n<li>Pytest collects test functions and methods that are prefixed with <code>test<\/code>, as well as <code>test<\/code> prefixed test functions and modules inside <code>Test<\/code> prefixed test classes that do not have a <code>__init__<\/code> method, from these files.<\/li>\n\n\n\n<li>Pytest also finds tests in subdirectories, making it simple to organize your tests within the context of your project structure.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Why do Most Prefer pytest?<\/h2>\n\n\n\n<p>If you&#8217;ve used the <code>unittest<\/code> library before, you&#8217;ll know that even writing a small test requires more code than <code>pytest<\/code>. Here&#8217;s an example to demonstrate.<\/p>\n\n\n\n<p>Assume you want to write a <code>unittest<\/code> test suite to test your code.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"test_unittest.py\"># test_unittest.py\n\nimport unittest\n\nclass TestWithUnittest(unittest.TestCase):\n    def test_query(self):\n        sentence = \"Welcome to GeekPython\"\n        self.assertTrue(\"P\" in sentence)\n        self.assertFalse(\"e\" in sentence)\n\n    def test_capitalize(self):\n        self.assertEqual(\"geek\".capitalize(), \"Geek\")<\/pre><\/div>\n\n\n\n<p>Now, from the command line, run these tests with <code>unittest<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;python -m unittest test_unittest.py\n.F\n======================================================================\nFAIL: test_query (test_unittest.TestWithUnittest)\n----------------------------------------------------------------------\nTraceback (most recent call last):\n  File \"D:\\SACHIN\\Pycharm\\pytestt_lib\\test_unittest.py\", line 9, in test_query\n    self.assertFalse(\"e\" in sentence)\nAssertionError: True is not false\n\n----------------------------------------------------------------------\nRan 2 tests in 0.001s\n\nFAILED (failures=1)<\/pre><\/div>\n\n\n\n<p>As you can see, the <code>test_query<\/code> test failed while the <code>test_capitalize<\/code> test passed, as expected by the code.<\/p>\n\n\n\n<p>However, writing those tests requires more lines of code, which include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Importing the <code>unittest<\/code> module.<\/li>\n\n\n\n<li>A test class (<code>TestWithUnittest<\/code>) is created by subclassing <code>TestCase<\/code>.<\/li>\n\n\n\n<li>Making assertions with unittest&#8217;s <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/geekpython.in\/python-assert\">assert<\/a> methods (<code>assertTrue<\/code>, <code>assertFalse<\/code>, and <code>assertEqual<\/code>).<\/li>\n<\/ul>\n\n\n\n<p>However, this is not the case with <code>pytest<\/code>, if you wrote those tests with <code>pytest<\/code>, they must look like this:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"test_pytest.py\"># test_pytest.py\n\ndef test_query():\n    sentence = \"Welcome to GeekPython\"\n    assert \"P\" in sentence\n    assert \"e\" not in sentence\n\n\ndef test_capitalize():\n    assert \"geek\".capitalize(), \"Geek\"<\/pre><\/div>\n\n\n\n<p>It&#8217;s as simple as that, there&#8217;s no need to import the package or use pre-defined assertion methods. With a detailed description, you will get a nicer output.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest\n====================================================================== test session starts =======================================================================\nplatform win32 -- Python 3.10.5, pytest-7.3.2, pluggy-1.0.0\nrootdir: D:\\SACHIN\\Pycharm\\pytestt_lib\nplugins: anyio-3.6.2\ncollected 2 items\n\ntest_pytest.py F.                                                                                                                                           [100%]\n\n============================================================================ FAILURES ============================================================================ \n___________________________________________________________________________ test_query ___________________________________________________________________________ \n\n    def test_query():\n        sentence = \"Welcome to GeekPython\"\n        assert \"P\" in sentence\n&gt;       assert \"e\" not in sentence\nE       AssertionError: assert 'e' not in 'Welcome to GeekPython'\nE         'e' is contained here:\nE           Welcome to GeekPython\nE         ?  +\n\ntest_pytest.py:6: AssertionError\n==================================================================== short test summary info ===================================================================== \nFAILED test_pytest.py::test_query - AssertionError: assert 'e' not in 'Welcome to GeekPython'\n================================================================== 1 failed, 1 passed in 0.31s ===================================================================<\/pre><\/div>\n\n\n\n<p>The following information can be found in the output:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The platform on which the test is run, the library versions used, the root directory where the test files are stored, and the plugins used.<\/li>\n\n\n\n<li>The Python file from the test, in this case, <code>test_pytest.py<\/code>, was collected.<\/li>\n\n\n\n<li>The test result, which is a <code>\"F\"<\/code> and a dot (<code>.<\/code>). An <code>\"F\"<\/code> indicates a <strong>failed test<\/strong>, a dot (<code>.<\/code>) indicates a <strong>passed test<\/strong>, and a <code>\"E\"<\/code> indicates an <strong>unexpected condition that occurred during testing<\/strong>.<\/li>\n\n\n\n<li>Finally, a test summary, which prints the results of the tests.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Parametrize Tests<\/h2>\n\n\n\n<p>What exactly is parametrization? <strong>Parametrization<\/strong> is the process of running multiple sets of tests on the same test function or class, each with a different set of parameters or arguments. This allows you to test the expected results of different input values.<\/p>\n\n\n\n<p>If you want to write multiple tests to evaluate various arguments for the <code>square<\/code> function, your first thought might be to write them as follows:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \"># Function to return the square of specified number\ndef square(num):\n    return num ** 2\n\n# Evaluating square of different numbers\ndef test_square_of_int():\n    assert square(5) == 25\n\ndef test_square_of_float():\n    assert square(5.2) == 27.04\n\ndef test_square_of_complex_num():\n    assert square(5j+5) == 50j\n\ndef test_square_of_string():\n    assert square(\"5\") == \"25\"<\/pre><\/div>\n\n\n\n<p>But wait, there&#8217;s a twist, <code>pytest<\/code> saves you from writing even more boilerplate code. To allow the parametrization of arguments for a test function, <code>pytest<\/code> provides the <code>@pytest.mark.parametrize<\/code> decorator.<\/p>\n\n\n\n<p>Using parametrization, you can eliminate code duplication and significantly reduce your test code.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python mark:6 decode:true \">import pytest\n\ndef square(num):\n    return num ** 2\n\n@pytest.mark.parametrize(\"num, expected\", [\n    (5, 25),\n    (5.2, 27.04),\n    (5j + 5, 50j),\n    (\"5\", \"25\")\n])\ndef test_square(num, expected):\n    assert square(num) == expected<\/pre><\/div>\n\n\n\n<p>The <code>@pytest.mark.parametrize<\/code> decorator defines four different (<code>\"num, expected\"<\/code>) tuples in the preceding code. The <code>test_square<\/code> test function will execute each of them one at a time, and the test report will be generated by determining whether the <code>num<\/code> evaluated is equal to the expected value.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Pytest Fixtures<\/h2>\n\n\n\n<p>Using <code>pytest<\/code> fixtures, you can avoid duplicating setup code across multiple tests. By defining a function with the <code>@pytest.fixture<\/code> decorator, you create a reusable setup that can be shared across multiple test functions or classes.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>In testing, a <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/en.wikipedia.org\/wiki\/Test_fixture#Software\">fixture<\/a> provides a defined, reliable, and consistent context for the tests. This could include environment (for example a database configured with known parameters) or content (such as a dataset). <a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/docs.pytest.org\/en\/7.4.x\/explanation\/fixtures.html#about-fixtures\">Source<\/a><\/p>\n<\/blockquote>\n\n\n\n<p>Here&#8217;s an example of when you should use fixtures. Assume you have a continuous stream of dynamic vehicle data and want to write a function <code>collect_vehicle_number_from_delhi()<\/code> to extract vehicle numbers belonging to Delhi.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"fixtures_pytest.py\"># fixtures_pytest.py\ndef collect_vehicle_number_from_delhi(vehicle_detail):\n    data_collected = []\n    for item in vehicle_detail:\n        vehicle_number = item.get(\"vehicle_number\", \"\")\n        if \"DL\" in vehicle_number:\n            data_collected.append(f\"{vehicle_number}\")\n    return data_collected<\/pre><\/div>\n\n\n\n<p>To check whether the function works properly, you would write a test that looks like the following:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"test_pytest_fixture.py\"># test_pytest_fixture.py\nfrom fixtures_pytest import collect_vehicle_number_from_delhi\n\ndef test_collect_vehicle_number_from_delhi():\n    vehicle_detail = [\n        {\n            \"category\": \"Car\",\n            \"vehicle_number\": \"DL04R1441\"\n        },\n\n        {\n            \"category\": \"Bike\",\n            \"vehicle_number\": \"HR04R1441\"\n        },\n\n        {\n            \"category\": \"Car\",\n            \"vehicle_number\": \"DL04R1541\"\n        }\n    ]\n\n    expected_result = [\n        \"DL04R1441\",\n        \"DL04R1541\"\n    ]\n\n    assert collect_vehicle_number_from_delhi(vehicle_detail) == expected_result<\/pre><\/div>\n\n\n\n<p>The test function <code>test_collect_vehicle_number_from_delhi()<\/code> above determines whether or not the <code>collect_vehicle_number_from_delhi()<\/code> function extracts the data as expected. Now you might want to extract the vehicle number belonging to another state, then you will write another function <code>collect_vehicle_number_from_haryana()<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"fixtures_pytest.py\"># fixtures_pytest.py\ndef collect_vehicle_number_from_delhi(vehicle_detail):\n    # Remaining code\n\ndef collect_vehicle_number_from_haryana(vehicle_detail):\n    data_collected = []\n    for item in vehicle_detail:\n        vehicle_number = item.get(\"vehicle_number\", \"\")\n        if \"HR\" in vehicle_number:\n            data_collected.append(f\"{vehicle_number}\")\n    return data_collected<\/pre><\/div>\n\n\n\n<p>Following the creation of this function, you will create another test function and repeat the process.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"test_pytest_fixture.py\"># test_pytest_fixture.py\nfrom fixtures_pytest import collect_vehicle_number_from_haryana\n\ndef test_collect_vehicle_number_from_haryana():\n    vehicle_detail = [\n        {\n            \"category\": \"Car\",\n            \"vehicle_number\": \"DL04R1441\"\n        },\n\n        {\n            \"category\": \"Bike\",\n            \"vehicle_number\": \"HR04R1441\"\n        },\n\n        {\n            \"category\": \"Car\",\n            \"vehicle_number\": \"DL04R1541\"\n        }\n    ]\n\n    expected_result = [\n        \"HR04R1441\"\n    ]\n\n    assert collect_vehicle_number_from_haryana(vehicle_detail) == expected_result<\/pre><\/div>\n\n\n\n<p>This is analogous to repeatedly writing the same code. To avoid writing the same code multiple times, create a function decorated with <code>@pytest.fixture<\/code> here.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python mark:7 decode:true \" title=\"test_pytest_fixture.py\"># test_pytest_fixture.py\n\nimport pytest\nfrom fixtures_pytest import collect_vehicle_number_from_haryana\nfrom fixtures_pytest import collect_vehicle_number_from_delhi\n\n@pytest.fixture\ndef vehicle_data():\n    return [\n        {\n            \"category\": \"Car\",\n            \"vehicle_number\": \"DL04R1441\"\n        },\n\n        {\n            \"category\": \"Bike\",\n            \"vehicle_number\": \"HR04R1441\"\n        },\n\n        {\n            \"category\": \"Car\",\n            \"vehicle_number\": \"DL04R1541\"\n        }\n    ]\n\n# test 1\ndef test_collect_vehicle_number_from_delhi(vehicle_data):\n    expected_result = [\n        \"DL04R1441\",\n        \"DL04R1541\"\n    ]\n    assert collect_vehicle_number_from_delhi(vehicle_data) == expected_result\n\n# test 2\ndef test_collect_vehicle_number_from_haryana(vehicle_data):\n    expected_result = [\n        \"HR04R1441\"\n    ]\n    assert collect_vehicle_number_from_haryana(vehicle_data) == expected_result<\/pre><\/div>\n\n\n\n<p>As you can see from the code above, the number of lines has been reduced to some extent, and you can now write a few more tests by reusing the <code>@pytest.fixture<\/code> decorated function <code>vehicle_data<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Fixture for Database Connection<\/h3>\n\n\n\n<p>Consider the example of creating a database connection, in which a fixture is used to set up the resources and then tear them down.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"fixture_for_db_connection.py\"># fixture_for_db_connection.py\n\nimport pytest\nimport sqlite3\n\n@pytest.fixture\ndef database_connection():\n    # Setup Phase\n    conn = sqlite3.connect(\":memory:\")\n    cur = conn.cursor()\n\n    cur.execute(\n        \"CREATE TABLE users (name TEXT)\"\n    )\n\n    # Freeze the state and pass the object to test function\n    yield conn\n\n    # Teardown Phase\n    conn.close()<\/pre><\/div>\n\n\n\n<p>A fixture <code>database_connection()<\/code> is created, which creates an SQLite database in memory and establishes a connection, then creates a table, yields the connection, and finally closes the connection once the work is completed.<\/p>\n\n\n\n<p>This fixture can be passed as an argument to the test function. Assume you want to write a function to insert a value into a database, simply do the following:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"fixture_for_db_connection.py\"># fixture_for_db_connection.py\n\ndef test_insert_data(database_connection):\n    database_connection.execute(\n        \"INSERT INTO users (name) VALUES ('Virat Kohli')\"\n    )\n\n    res = database_connection.execute(\n        \"SELECT * FROM users\"\n    )\n    result = res.fetchall()\n\n    assert result is not None\n    assert (\"Virat Kohli\",) in result<\/pre><\/div>\n\n\n\n<p>The <code>test_insert_data()<\/code> test function takes the <code>database_connection<\/code> fixture as an argument, which eliminates the need to rewrite the database connection code.<\/p>\n\n\n\n<p>You can now write as many test functions as you want without having to rewrite the database setup code.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Markers in Pytest<\/h2>\n\n\n\n<p>Pytest provides a few built-in markers to mark your test functions which can be handy while testing.<\/p>\n\n\n\n<p>In the earlier section, you saw the parametrization of arguments using the <code>@pytest.mark.parametrize<\/code> decorator. Well, <code>@pytest.mark.parametrize<\/code> is a decorator that marks a test function for parametrization.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Skipping Tests<\/h3>\n\n\n\n<p>If you have a test function that you want to skip during testing for some reason, you can decorate it with <code>@pytest.mark.skip<\/code>.<\/p>\n\n\n\n<p>In the <code>test_pytest_fixture.py<\/code> script, for example, you added two new test functions but want to skip testing them because you haven&#8217;t yet created the <code>collect_vehicle_number_from_punjab()<\/code> and <code>collect_vehicle_number_from_maharashtra()<\/code> functions to pass these tests.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python mark:5,13 decode:true \" title=\"test_pytest_fixture.py\"># test_pytest_fixture.py\n\n# Previous code here\n\n@pytest.mark.skip(reason=\"Not implemented yet\")\ndef test_collect_vehicle_number_from_punjab(vehicle_data):\n    expected_result = [\n        \"PB3SQ4141\"\n    ]\n    assert collect_vehicle_number_from_punjab(vehicle_data) == expected_result\n\n\n@pytest.mark.skip(reason=\"Not implemented yet\")\ndef test_collect_vehicle_number_from_maharashtra(vehicle_data):\n    expected_result = [\n        \"MH05X1251\"\n    ]\n    assert collect_vehicle_number_from_maharashtra(vehicle_data) == expected_result<\/pre><\/div>\n\n\n\n<p>Both test functions in this script are marked with <code>@pytest.mark.skip<\/code> and provide a reason for skipping. When you run this script, pytest will bypass these tests.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest test_pytest_fixture.py\n====================================================================== test session starts =======================================================================\nplatform win32 -- Python 3.10.5, pytest-7.3.2, pluggy-1.0.0\nrootdir: D:\\SACHIN\\Pycharm\\pytestt_lib\nplugins: anyio-3.6.2\ncollected 4 items\n\ntest_pytest_feature.py ..ss                                                                                                                                 [100%]\n\n================================================================== 2 passed, 2 skipped in 0.05s ==================================================================<\/pre><\/div>\n\n\n\n<p>The report shows that two tests were passed and two were skipped.<\/p>\n\n\n\n<p>If you want to conditionally skip a test function. In that case, use the <code>@pytest.mark.skipif<\/code> decorator to mark the test function. Here&#8217;s an illustration.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python mark:5-8,16-19 decode:true \" title=\"test_pytest_fixture.py\"># test_pytest_fixture.py\n\n# Previous code here\n\n@pytest.mark.skipif(\n    pytest.version_tuple &lt; (7, 2), \n    reason=\"pytest version is less than 7.2\"\n)\ndef test_collect_vehicle_number_from_punjab(vehicle_data):\n    expected_result = [\n        \"PB3SQ4141\"\n    ]\n    assert collect_vehicle_number_from_punjab(vehicle_data) == expected_result\n\n\n@pytest.mark.skipif(\n    pytest.version_tuple &lt; (7, 2), \n    reason=\"pytest version is less than 7.2\"\n)\ndef test_collect_vehicle_number_from_karnataka(vehicle_data):\n    expected_result = [\n        \"KR3SQ4141\"\n    ]\n    assert collect_vehicle_number_from_karnataka(vehicle_data) == expected_result<\/pre><\/div>\n\n\n\n<p>In this example, two test functions (<code>test_collect_vehicle_number_from_punjab<\/code> and <code>test_collect_vehicle_number_from_karnataka<\/code>) are decorated with <code>@pytest.mark.skipif<\/code>. The condition specified in each case is <code>pytest.version_tuple &lt; (7, 2)<\/code>, which means that these tests will be skipped if the installed <code>pytest<\/code> version is less than 7.2. The <code>reason<\/code> parameter provides a message explaining why the tests are being skipped.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Filter Warnings<\/h3>\n\n\n\n<p>You can add warning filters to specific test functions or classes using the <code>@pytest.mark.filterwarnings<\/code> function, allowing you to control which warnings are captured during tests.<\/p>\n\n\n\n<p>Here&#8217;s an example of the code from above.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python mark:10,17 decode:true \" title=\"test_pytest_fixture.py\"># test_pytest_fixture.py\nimport warnings\n\n# Previous code here\n\n# Helper warning function\ndef warning_function():\n    warnings.warn(\"Not implemented yet\", UserWarning)\n\n@pytest.mark.filterwarnings(\"error:Not implemented yet\")\ndef test_collect_vehicle_number_from_punjab(vehicle_data):\n    warning_function()\n    expected_result = [\"PB3SQ4141\"]\n    assert collect_vehicle_number_from_punjab(vehicle_data) == expected_result\n\n\n@pytest.mark.filterwarnings(\"error:Not implemented yet\")\ndef test_collect_vehicle_number_from_karnataka(vehicle_data):\n    warning_function()\n    expected_result = [\"KR3SQ4141\"]\n    assert collect_vehicle_number_from_karnataka(vehicle_data) == expected_result<\/pre><\/div>\n\n\n\n<p>In this example, a warning message is emitted by a helper warning function (<code>warning_function()<\/code>).<\/p>\n\n\n\n<p>Both test functions (<code>test_collect_vehicle_number_from_punjab<\/code> and <code>test_collect_vehicle_number_from_karnataka<\/code>) are decorated with <code>@pytest.mark.filterwarnings<\/code> which specifies that any <code>UserWarning<\/code> with the message <strong>&#8220;Not implemented yet&#8221;<\/strong> should be treated as an error during the execution of these tests.<\/p>\n\n\n\n<p>These test functions call <code>warning_function<\/code> which, in turn, emits a <code>UserWarning<\/code> with the specified message.<\/p>\n\n\n\n<p>You can see in the summary of the report generated by <code>pytest<\/code>, the warning is displayed.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">==================================================================== short test summary info ===================================================================== \nFAILED test_pytest_feature.py::test_collect_vehicle_number_from_punjab - UserWarning: Not implemented yet\nFAILED test_pytest_feature.py::test_collect_vehicle_number_from_karnataka - UserWarning: Not implemented yet\n======================================================================= 2 failed in 0.31s ========================================================================<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Pytest Command-line Options<\/h2>\n\n\n\n<p>Pytest provides numerous command-line options that allow you to customize or extend the behavior of test execution. You can list all the available <code>pytest<\/code> options using the following command in your terminal.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">pytest --help<\/pre><\/div>\n\n\n\n<p>Here are some <code>pytest<\/code> command-line options that you can try when you execute tests.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Running Tests Using Keyword<\/h3>\n\n\n\n<p>You can specify which tests to run by following the <code>-k<\/code> option with a keyword or expression. Assume you have the Python file <code>test_sample.py<\/code>, which contains the tests listed below.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \" title=\"test_sample.py\">def square(num):\n    return num**2\n\n# Test 1\ndef test_special_one():\n    a = 2\n    assert square(a) == 4\n\n# Test 2\ndef test_special_two():\n    x = 3\n    assert square(x) == 9\n\n# Test 3\ndef test_normal_three():\n    x = 3\n    assert square(x) == 9<\/pre><\/div>\n\n\n\n<p>If you want to run tests that contain <code>\"test_special\"<\/code>, use the following command.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest -k test_special                \n====================================================================== test session starts =======================================================================\nplatform win32 -- Python 3.10.5, pytest-7.3.2, pluggy-1.0.0\nrootdir: D:\\SACHIN\\Pycharm\\pytestt_lib\nplugins: anyio-3.6.2\ncollected 3 items \/ 1 deselected \/ 2 selected\n\ntest_sample.py ..                                                                                                                                           [100%]\n\n================================================================ 2 passed, 1 deselected in 0.07s =================================================================<\/pre><\/div>\n\n\n\n<p>The tests that have <code>\"test_special\"<\/code> in their name were selected, and the others were deselected.<\/p>\n\n\n\n<p>If you want to run all other tests but not the ones with &#8220;test_special&#8221; in their names, use the following command.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest -k \"not test_special\"\n====================================================================== test session starts =======================================================================\nplatform win32 -- Python 3.10.5, pytest-7.3.2, pluggy-1.0.0\nrootdir: D:\\SACHIN\\Pycharm\\pytestt_lib\nplugins: anyio-3.6.2\ncollected 3 items \/ 2 deselected \/ 1 selected\n\ntest_sample.py .                                                                                                                                            [100%] \n\n================================================================ 1 passed, 2 deselected in 0.06s =================================================================<\/pre><\/div>\n\n\n\n<p>The expression <code>\"not test_special\"<\/code> in the above command indicates that run only those tests that don&#8217;t have &#8220;test_special&#8221; in their name.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Customizing Output<\/h3>\n\n\n\n<p>You can use the following options to customize the output and the report:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>-v<\/code>, <code>--verbose<\/code> &#8211; Increases verbosity<\/li>\n\n\n\n<li><code>--no-header<\/code> &#8211; Disables header<\/li>\n\n\n\n<li><code>--no-summary<\/code> &#8211; Disables summary<\/li>\n\n\n\n<li><code>-q<\/code>, <code>--quiet<\/code> &#8211; Decreases verbosity<\/li>\n<\/ul>\n\n\n\n<p><strong>Output of the tests with increased verbosity.<\/strong><\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest -v test_sample.py \n====================================================================== test session starts =======================================================================\nplatform win32 -- Python 3.10.5, pytest-7.3.2, pluggy-1.0.0 -- D:\\SACHIN\\Python310\\python.exe\ncachedir: .pytest_cache\nrootdir: D:\\SACHIN\\Pycharm\\pytestt_lib\nplugins: anyio-3.6.2\ncollected 3 items                                                                                                                                                  \n\ntest_sample.py::test_special_one PASSED                                                                                                                     [ 33%] \ntest_sample.py::test_special_two PASSED                                                                                                                     [ 66%] \ntest_sample.py::test_normal_three PASSED                                                                                                                    [100%] \n\n======================================================================= 3 passed in 0.04s ========================================================================<\/pre><\/div>\n\n\n\n<p><strong>Output of the tests with decreased verbosity.<\/strong><\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest -q test_sample.py \n...                                                                                                                                                         [100%]\n3 passed in 0.02s<\/pre><\/div>\n\n\n\n<p>When you use <code>--no-header<\/code> and <code>--no-summary<\/code> together, it is equivalent to using <code>-q<\/code> (decreased verbosity).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Test Collection<\/h3>\n\n\n\n<p>Using the <code>--collect-only<\/code>, <code>--co<\/code> option, <code>pytest<\/code> collects all the tests but doesn&#8217;t execute them.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest --collect-only test_sample.py           \n====================================================================== test session starts =======================================================================\nplatform win32 -- Python 3.10.5, pytest-7.3.2, pluggy-1.0.0\nrootdir: D:\\SACHIN\\Pycharm\\pytestt_lib\nplugins: anyio-3.6.2\ncollected 3 items\n\n&lt;Module test_sample.py&gt;\n  &lt;Function test_special_one&gt;\n  &lt;Function test_special_two&gt;\n  &lt;Function test_normal_three&gt;\n\n=================================================================== 3 tests collected in 0.02s ===================================================================<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Ignore Path or File during Test Collection<\/strong><\/h3>\n\n\n\n<p>If you don&#8217;t want to collect tests from a specific path or file, use the <code>--ignore=path<\/code> option.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest --ignore=test_sample.py\n====================================================================== test session starts =======================================================================\nplatform win32 -- Python 3.10.5, pytest-7.3.2, pluggy-1.0.0\nrootdir: D:\\SACHIN\\Pycharm\\pytestt_lib\nplugins: anyio-3.6.2\ncollected 1 item\n\ntest_square.py .                                                                                                                                            [100%] \n\n======================================================================= 1 passed in 0.06s ========================================================================<\/pre><\/div>\n\n\n\n<p>The <code>test_sample.py<\/code> file is ignored by <code>pytest<\/code> during test collection in the above example.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Exit on First Failed Test or Error<\/h3>\n\n\n\n<p>When you use the <code>-x<\/code>, <code>--exitfirst<\/code> option, <code>pytest<\/code> exits the test execution on the first failed test or error that it finds.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:python decode:true \">D:\\SACHIN\\Pycharm\\pytestt_lib&gt;pytest -x test_sample.py\n====================================================================== test session starts =======================================================================\nplatform win32 -- Python 3.10.5, pytest-7.3.2, pluggy-1.0.0\nrootdir: D:\\SACHIN\\Pycharm\\pytestt_lib\nplugins: anyio-3.6.2\ncollected 3 items\n\ntest_sample.py F\n\n============================================================================ FAILURES ============================================================================ \n________________________________________________________________________ test_special_one ________________________________________________________________________ \n\n    def test_special_one():\n        a = 2\n&gt;       assert square(a) == 5\nE       assert 4 == 5\nE        +  where 4 = square(2)\n\ntest_sample.py:6: AssertionError\n==================================================================== short test summary info ===================================================================== \nFAILED test_sample.py::test_special_one - assert 4 == 5\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! \n======================================================================= 1 failed in 0.35s ========================================================================<\/pre><\/div>\n\n\n\n<p>Pytest immediately exits the test execution when it finds a failed test and a stopping message appears in the report summary.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Pytest is a testing framework that allows you to write small and readable tests to test or debug your code.<\/p>\n\n\n\n<p>In this article, you&#8217;ve learned:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>How to use <code>pytest<\/code> for testing your code<\/li>\n\n\n\n<li>How to parametrize arguments to avoid code duplication<\/li>\n\n\n\n<li>How to use fixtures in <code>pytest<\/code><\/li>\n\n\n\n<li>Pytest command-line options<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>\ud83c\udfc6<strong>Other articles you might be interested in if you liked this one<\/strong><\/p>\n\n\n\n<p>\u2705<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/geekpython.in\/unit-tests-in-python\">Debug\/Test your code using the unittest module in Python<\/a>.<\/p>\n\n\n\n<p>\u2705<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/geekpython.in\/python-assert\">What is assert in Python and how to use it for debugging<\/a>?<\/p>\n\n\n\n<p>\u2705<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/geekpython.in\/build-websocket-server-and-client-using-python\">Create a WebSocket server and client in Python<\/a>.<\/p>\n\n\n\n<p>\u2705<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/geekpython.in\/threading-module-to-create-threads-in-python\">Create multi-threaded Python programs using a threading module<\/a>.<\/p>\n\n\n\n<p>\u2705<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/geekpython.in\/create-and-integrate-mysql-database-with-flask-app\">Create and integrate MySQL database with Flask app using Python<\/a>.<\/p>\n\n\n\n<p>\u2705<a target=\"_blank\" rel=\"noreferrer noopener\" href=\"https:\/\/geekpython.in\/render-images-from-flask\">Upload and display images on the frontend using Flask<\/a>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>That&#8217;s all for now<\/strong><\/p>\n\n\n\n<p><strong>Keep Coding\u270c\u270c<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>You may have done unit testing or heard the term unit test, which involves breaking down your code into smaller units and testing them to see if they are producing the correct output. Python has a robust unit testing library called unittest that provides a comprehensive set of testing features. However, some developers believe that [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1592,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ocean_post_layout":"","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"","ocean_second_sidebar":"","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"","ocean_custom_header_template":"","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"","ocean_menu_typo_font_family":"","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":"","ocean_post_oembed":"","ocean_post_self_hosted_media":"","ocean_post_video_embed":"","ocean_link_format":"","ocean_link_format_target":"self","ocean_quote_format":"","ocean_quote_format_link":"post","ocean_gallery_link_images":"on","ocean_gallery_id":[],"footnotes":""},"categories":[67,2],"tags":[12,75],"class_list":["post-1590","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-testing","category-python","tag-python","tag-testing","entry","has-media"],"_links":{"self":[{"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/posts\/1590","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/comments?post=1590"}],"version-history":[{"count":10,"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/posts\/1590\/revisions"}],"predecessor-version":[{"id":1602,"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/posts\/1590\/revisions\/1602"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/media\/1592"}],"wp:attachment":[{"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/media?parent=1590"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/categories?post=1590"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/geekpython.in\/wp-json\/wp\/v2\/tags?post=1590"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}