DEV Community

Mingming Ma
Mingming Ma

Posted on

Pytest practices

Pytest is a popular testing framework for Python. It has a clean and easy-to-understand syntax, making it accessible for beginners while providing advanced features for more complex testing scenarios. I would like to share my testing process using Pytest.

Prepare for testing

Install Pytest from command

pip3 install pytest
Enter fullscreen mode Exit fullscreen mode

Project structure

Then we should make sure our testing environment is working. Let's look my sample test structure:

project/
├── sample.py
└── tests/
    └── sample_test.py
    └── __init__.py
Enter fullscreen mode Exit fullscreen mode

Note that the __init__.py in tests folder is to let Pytest find the module correctly, without that, you may encounter this error:

tests/sample_test.py:2: in <module>
    import sample
E   ModuleNotFoundError: No module named 'sample'
Enter fullscreen mode Exit fullscreen mode

The example tests are some basic check, like:

# sample.py
def square(x: float) -> float:
    return x * x
Enter fullscreen mode Exit fullscreen mode
# tests/sample_test.py
import sample


def test_square():
    assert sample.square(5) == 25

Enter fullscreen mode Exit fullscreen mode

Then we can run the test command at project root folder:

pytest # Or pytest <test file>.py for one specific file
Enter fullscreen mode Exit fullscreen mode

The test result should be like

 % pytest
================================================================ test session starts ================================================================
platform darwin -- Python 3.11.5, pytest-7.4.3, pluggy-1.3.0
rootdir: /Users/name/path/to/project
plugins: anyio-3.7.1
collected 1 item                                                                                                                                    

tests/sample_test.py .                                                                                                                        [100%]

================================================================= 1 passed in 0.01s =================================================================
Enter fullscreen mode Exit fullscreen mode

Test my project functions

I tested my process_line function with the following test case:

import pytest
from txt2html import process_line


@pytest.mark.parametrize(
    "input_line, expected_output",
    [
        ("This is a normal line.", "This is a normal line."),
        ("*This should be italic.*", "<i>This should be italic.</i>"),
        ("**This should not be bold.**", "**This should not be bold.**"),
        (
            "*Multiple* *italics* *in* *one* *line.*",
            "<i>Multiple</i> <i>italics</i> <i>in</i> <i>one</i> <i>line.</i>",
        ),
        ("No italics in this line.", "No italics in this line."),
    ],
)
def test_process_line(input_line, expected_output):
    result = process_line(input_line)
    assert result == expected_output

Enter fullscreen mode Exit fullscreen mode

And it gave me results that my code has errors: (I found the summary info is good enough for me to know the issue)

============================================================== short test summary info ==============================================================
FAILED tests/test_process_line.py::test_process_line[This is a normal line.-This is a normal line.] - AssertionError: assert 'This is a normal line. ' == 'This is a normal line.'
FAILED tests/test_process_line.py::test_process_line[*This should be italic.*-<i>This should be italic.</i>] - AssertionError: assert '*This should be italic.* ' == '<i>This shou...e italic.</i>'
FAILED tests/test_process_line.py::test_process_line[**This should not be bold.**-**This should not be bold.**] - AssertionError: assert '**This shoul...t be bold.** ' == '**This should not be bold.**'
FAILED tests/test_process_line.py::test_process_line[*Multiple* *italics* *in* *one* *line.*-<i>Multiple</i> <i>italics</i> <i>in</i> <i>one</i> <i>line.</i>] - AssertionError: assert '<i>Multiple<...<i>line.</i> ' == '<i>Multiple<... <i>line.</i>'
FAILED tests/test_process_line.py::test_process_line[No italics in this line.-No italics in this line.] - AssertionError: assert 'No italics in this line. ' == 'No italics in this line.'
================================================================= 5 failed in 0.05s =================================================================
Enter fullscreen mode Exit fullscreen mode

Here I realized my code always added a tailing space, which is not as expected. After adding strip() to remove space, I run again and this time it give me another error:

============================================================== short test summary info ==============================================================
FAILED tests/test_process_line.py::test_process_line[This should be *italic*.-This should be <i>italic</i>.] - AssertionError: assert 'This should ...i>italic*</i>' == 'This should ...i>italic</i>.'
============================================================ 1 failed, 4 passed in 0.04s ============================================================
Enter fullscreen mode Exit fullscreen mode

This shows me my code has bugs cannot convert to italic at this situation: the * has connected with an symbol .

*word*.
Enter fullscreen mode Exit fullscreen mode

This is so great! The test cases seamlessly steering me through potential pitfalls and making debugging an enjoyable challenge. Now I'm going to find out how to deal with that bug.

Top comments (0)