Weekly Programming Topics
Testing, Tools and Projects
Week 12 – Testing, Tools and Projects · Table content
Testing, Tools and Projects
Week 12 – Testing, Tools and Projects
Table content
- Testing tools
- pytest recap
- pytest fixture
- pytest parametrize (data-driven tests)
- unittest – the alternative
- unittest assertions cheat sheet
- Exception handling
- Debug with breakpoint
- Profiling
- Packages
1.1 pytest recap
A quick recap on pytest from the previous week:
- Python's most widely used testing tool
- Almost nothing to set up: no class to inherit, no special methods to memorise
- You write plain functions and use plain assert
- When your code is wrong, pytest tells you exactly why
- Run pytest_example_1.py for details
1.2 pytest fixture
- Most tests need shared setup: a fresh object, a temp file, etc
- pytest automatically calls it and injects it into any test that asks for it by name
- fixtures are reusable across multiple test files and can depend on each other
- Run pytest_example_2.py for details
1.3 pytest parametrize (data-driven tests)
- A common mistake is writing nearly identical tests that differ only in input values table of inputs
- pytest runs it as a separate, independently reported test for every row
- If one case fails, the others still run
- Run pytest_example_3.py for details
- 1.4 unittest
- the alternative
- Ships with Python – nothing to install
- Directly inspired by Java's Junit
- Inherit from unittest.TestCase, write setUp/tearDown, call named assertion methods
- Run unittest_example.py for details
1.5 unittest assertions cheat sheet
- Where pytest uses plain assert, unittest has a dedicated method for every kind of check
- More verbose, but unittest always knows what kind of assertion failed => error messages are clearer
Method Example Meaning
assertEqual(a, b) self.assertEqual(x1, 3.0) a equals b assertNotEqual(a, b) self.assertNotEqual(x1, 0) a does not equal b
assertIsNone(obj) self.assertIsNone(result) obj is None assertIsNotNone(obj) self.assertIsNotNone(resul t) obj is not None
assertTrue(condition) self.assertTrue(x1 > 0) condition is True assertFalse(condition) self.assertFalse(x1 < 0) condition is False
assertIsInstance(obj, class)
self.assertIsInstance(x1,
float) obj is an instance of class assertRegex(str, regex) self.assertRegex(name, r"^A") string matches regex assertNotRegex(str, regex) self.assertNotRegex(name, r"^Z") string does not match regex assertIn(obj, col) self.assertIn(3.0, roots) obj is in the collection assertNotIn(obj, col) self.assertNotIn(0, roots) obj is not in the collection assertRaises(Err) with self.assertRaises(ValueErr or): code raises the exception
- Exception handling
- A program crashes when something unexpected happens. For instance: a file doesn't exist, a network is down, a user types the wrong thing
- Without exception handling the program just stops with an ugly error message
- Exception handling lets you catch the error, respond to it gracefully, and keep the program running
- In Python exceptions are handled with try / except
- Exception handling (cont.)
- Wrap risky code in try
- Catch the error in except
- Optionally use else for code that runs only if no error occurred
- Optionally use finally for code that always runs, error or not
- Exception handling (cont.)
- else runs only when no exception was raised – good for code that depends on success
- finally always runs – good for cleanup like closing files or database connections
- Run exception_handling_1.py for details
- Exception handling (cont.)
- Python has many built-in exception types — you catch only what you expect
- Catching too broadly hides bugs, so always be as specific as possible
Exception When it occurs
FileNotFoundError File or directory does not exist ValueError Right type but wrong value (e.g. int("abc")) TypeError Wrong type entirely (e.g. 1 + "a") ZeroDivisionError Dividing by zero IndexError List index out of range KeyError Dictionary key does not exist AttributeError Object has no such attribute or method ImportError Module cannot be found or imported PermissionError No permission to open a file
- Exception Catches everything
- use as a last resort only
- Exception handling (cont.)
- You can raise exceptions yourself to signal that something has gone wrong in your own code
- This is how quadratic.py signals that a negative discriminant has no real roots
- Debug with breakpoint
- Let’s open a_buggy_program.py file and run it.
- The program calculates student grades but crashes halfway through
- We need to find out what data caused the crash and why
- In VS Code or PyCharm, click the grey area to the left of the line number
- A red dot appears – this is a breakpoint
- Set it on the line avg = average(student["marks"]) inside the loop
- Now run the file in Debug mode(the play button with the bug icon, or
F5 in VS Code)
- Debug with breakpoint (cont.)
- When the program pauses, the IDE shows you all current variable values in the sidebar
- Step through the loop with F10 (Step Over) to advance one iteration at a time
- Watch the student variable change each iteration
Q: Can you spot the error when running iterate through the students list? Q: How to fix the error?
- Profiling
- A program can be correct but too slow; profiling tells you exactly where the time is being spent
- Without profiling you are guessing; optimising the wrong function wastes effort
- Python's built-in profiler is cProfile => no installation needed
- The command: python -m cProfile
- Let’s run our example with: python -m cProfile -s cumulative profiling_example.py
- -s cumulative to sort by cumulative time
- Packages
- In Python you can package reusable code and share it on PyPI (pypi.org)
- Anyone can then install your package with pip install yourpackage
- The package is defined in a single file called pyproject.toml
- Packages
- Create the folder structure and define your package in pyproject.toml
- Packages Two commands to build and publish (you may need to have “build” and “twine” installed and have an account on PyPI first)
- Build: python -m build
- Publish to PyPI: twine upload dist/*
- Anyone can now install it: pip install quadratic-cos10009-demo
- Our package has been published at:
https://pypi.org/project/quadratic-cos10009-demo/1.0.2/
- Packages Let’s test this out!
- Install it from PyPI: pip install quadratic-cos10009-demo
- Verify it installed correctly: pip show quadratic-cos10009-demo
- Import and play around