OSD600: Lab 7

This week I worked on adding some automated testing to the repository-context-manager.

Since the project is written entirely in Python, naturally I chose to use pytest as my testing framework. I had some experience with pytest from my previous interns…


This content originally appeared on DEV Community and was authored by Kyle Homen

This week I worked on adding some automated testing to the repository-context-manager.

Since the project is written entirely in Python, naturally I chose to use pytest as my testing framework. I had some experience with pytest from my previous internship and seems like the go-to option to write tests with. To be honest, I didn't even check if there was another option.

To get started with pytest, of course you need to install it. I used the pip installer to install it directly in VSCode terminal by running: pip install pytest.

Off the rip I was having some trouble running my first test, and found out that I needed to create a configuration file for pytest called conftest.py. With this configuration file, I needed to indicate the project root so that my test folder could interact with the analyzer module that held all of my code:

project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

With that out of the way, the first few tests were up and running. On my first test file, I decided to test the recently added remove lines feature that I added. I chose this function because I knew this one needed a little extra work to eventually add the ability to remove inline comments, and having some robust testing to make sure that feature works without removing, for example, strings with hash symbols inside them.

Here's an example of the one test that does not pass because that feature isn't added yet:

    def test_inline_hash_comment(self):
        """Test removal of inline hash comments."""
        code = 'x = 5  # This is an inline comment'
        expected = 'x = 5'
        assert remove_hash_comments(code) == expected

My second tested function looked at checking the output for logging messages, which involved using the built in caplog feature of pytest. At first I was not finding the messages that SHOULD have been properly logged, but after a bit of research I found that, by default, caplog is only capturing at the warning level, and my logging was at the debug level.

This was fixed by adding the debug level to the conftest.py file:

logging.basicConfig(level=logging.DEBUG)

After that, I could check the caplog output if a certain debug statement was triggered:

    def test_config_file_not_found(self, caplog):
        """Test behavior when config file doesn't exist."""
        assert load_config_file("/nonexistent/path/config.toml") == {}
        assert "No config file found" in caplog.text

Finally, when writing tests for my final function (the is recently modified function that checks if a file has been recently modified), I found that I was repeating code just checking the different inputs (using a mock filetime and setting a recent threshold). I found that pytest has a built in parametrization feature that allows you to write one unit test and feed it multiple parameters to test multiple inputs at once like so:

@pytest.mark.parametrize("days_ago,threshold,expected", [
    (1, 7, True),    # 1 day ago, 7-day threshold -> recent
    (5, 7, True),    # 5 days ago, 7-day threshold -> recent
    (10, 7, False),  # 10 days ago, 7-day threshold -> not recent
    (0.5, 1, True),  # 12 hours ago, 1-day threshold -> recent
    (2, 1, False),   # 2 days ago, 1-day threshold -> not recent
    (30, 30, True),  # 30 days ago, 30-day threshold -> recent
    (31, 30, False),  # 31 days ago, 30-day threshold -> not recent
])
def test_various_time_thresholds(days_ago, threshold, expected):
    """Test various combinations of file age and thresholds."""
    with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
        f.write("test")
        temp_path = f.name

    try:
        # Mock modification time
        mod_time = time.time() - (days_ago * 24 * 60 * 60)

        with patch('os.stat') as mock_stat:
            mock_stat.return_value = MagicMock(st_mtime=mod_time)

            result = is_recently_modified(temp_path, recent_day=threshold)

            assert result == expected
    finally:
        os.unlink(temp_path)

This test creates a temporary file, modifies the recently modified time, and passes it into the function being tested. This way, I could test many different combinations of recently modified times and thresholds.

During this process, I realized that I had some very tricky functions when it came to testing, and I see the benefits of writing the unit tests as I add features as it might have actually pushed me to modularize the code a lot more into testable parts. One of my output functions is so large that it's pretty much a write off trying to test it. I think I will definitely be keeping testing in mind when I write code from now on, as this was a bit of an eye opener.


This content originally appeared on DEV Community and was authored by Kyle Homen


Print Share Comment Cite Upload Translate Updates
APA

Kyle Homen | Sciencx (2025-11-07T17:12:23+00:00) OSD600: Lab 7. Retrieved from https://www.scien.cx/2025/11/07/osd600-lab-7/

MLA
" » OSD600: Lab 7." Kyle Homen | Sciencx - Friday November 7, 2025, https://www.scien.cx/2025/11/07/osd600-lab-7/
HARVARD
Kyle Homen | Sciencx Friday November 7, 2025 » OSD600: Lab 7., viewed ,<https://www.scien.cx/2025/11/07/osd600-lab-7/>
VANCOUVER
Kyle Homen | Sciencx - » OSD600: Lab 7. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/11/07/osd600-lab-7/
CHICAGO
" » OSD600: Lab 7." Kyle Homen | Sciencx - Accessed . https://www.scien.cx/2025/11/07/osd600-lab-7/
IEEE
" » OSD600: Lab 7." Kyle Homen | Sciencx [Online]. Available: https://www.scien.cx/2025/11/07/osd600-lab-7/. [Accessed: ]
rf:citation
» OSD600: Lab 7 | Kyle Homen | Sciencx | https://www.scien.cx/2025/11/07/osd600-lab-7/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.