For Lab 7, I added automated testing to my Repo Code Packager project. This tool analyzes Git repositories and generates formatted output for sharing with LLMs. Before this lab, I had no automated tests, which made it risky to add new features or refactor code. This lab taught me how to set up a testing framework and write test cases.
Choosing a Testing Framework
Since my project is written in Python, I researched several testing frameworks:
- unittest: Python's built-in testing framework
- nose: An extension of unittest (but less actively maintained)
- pytest: The most popular modern Python testing framework
I chose pytest for several reasons:
- Simple syntax: Uses plain assert statements instead of
self.assertEqual() - Great documentation: Easy to find examples and tutorials
- Powerful features: parametrization and well written error messages
Setting Up the Testing Environment
Following the lab instructions, I created a testing branch:
git checkout -b testing
├── tests/
│ ├── __init__.py
│ ├── test_file_utils.py
│ ├── test_content_packager.py
│ └── test_git_utils.py
The tests/__init__.py file is empty but necessary for Python to recognize the directory as a package.
Writing My First Tests
I started with file_utils.py because it contains pure functions with no external dependencies which makes perfect for learning unit testing.
is_recently_modified() function checks if a file was modified within a specified time window. Here's what I tested:
def test_nonexistent_file_returns_false(self):
"""Non-existent file should return False"""
result = is_recently_modified("nonexistent_file.txt")
assert result == False
def test_recently_created_file_returns_true(self, tmp_path):
"""Recently created file should return True"""
test_file = tmp_path / "recent.txt"
test_file.write_text("test content")
result = is_recently_modified(str(test_file), days=7)
assert result == True
I discovered pytest's tmp_path fixture, which creates a temporary directory for each test. This was incredibly useful because test don't leave files on my system and each test is isolated.
Testing Edge Cases
The most interesting test was checking old files:
def test_file_modified_beyond_time_window(self, tmp_path):
"""File modified beyond the time window should return False"""
test_file = tmp_path / "old.txt"
test_file.write_text("old content")
# Set modification time to 10 days ago
ten_days_ago = time.time() - (10 * 86400)
os.utime(str(test_file), (ten_days_ago, ten_days_ago))
result = is_recently_modified(str(test_file), days=7)
assert result == False
I learned about os.utime() which allows you to manipulate file timestamps. It is very useful for testing time-based functionality.
Bugs Discovered Through Testing
Bug #1: Missing Error Handler
When I wrote tests for git_utils.py, I discovered a bug:
NotADirectoryError: [WinError 267] The directory name is invalid
The problem was in my exception handling. The original code only caught subprocess.CalledProcessError and FileNotFoundError, but Windows throws NotADirectoryError for invalid paths.
Fix:
except (subprocess.CalledProcessError, FileNotFoundError, NotADirectoryError, IndexError, OSError):
return "Not a git repository"
This was actually my first time discovering cross-platform issue through formal testing procedure. When subprocess tries to run a git command with an invalid path on Windows, it raises NotADirectoryError instead. This wasn't being caught, causing the test to crash. Different operating systems can raise different exceptions for the same error condition. By adding NotADirectoryError and the more general OSError, my code now handles edge cases better.
Top comments (0)