Unit Tests#
Is a way to test the code you wrote.
Testing calculator.py#
Calculator.py code#
def main():
x = int(input("What's x? "))
print("x squared is", square(x))
def square(n):
return n * n
if __name__ == "__main__":
main()
test_calculator.py code#
from calculator import square
def main():
test_square()
def test_square():
if square(2) != 4:
print("2 squared is not 4")
if square(3) != 9:
print("3 squared is not 9")
if __name__ == "__main__":
main()
assert#
testing this code
def main():
test_square()
def test_square():
assert square(2) == 4
assert square(3) == 9
if __name__ == "__main__":
main()
AssertionError#
How to handle an AssertionError
First “bad” try#
testing this code
def main():
test_square()
def test_square():
try:
assert square(2) == 4
except AssertionError:
print("2 squared is not 4")
try:
assert square(3) == 9
except AssertionError:
print("3 squared is not 9")
if __name__ == "__main__":
main()
Second “bad” try with more examples#
testing this code
def main():
test_square()
def test_square():
try:
assert square(2) == 4
except AssertionError:
print("2 squared is not 4")
try:
assert square(3) == 9
except AssertionError:
print("3 squared is not 9")
try:
assert square(-3) == 9
except AssertionError:
print("-3 squared is not 9")
try:
assert square(0) == 0
except AssertionError:
print("0 squared is not 0")
if __name__ == "__main__":
main()
pytest#
Installation#
$ pip install pytest
Documentation#
Same test with pytest and all the tests in one function#
testing this code
from calculator import square
def test_square():
assert square(2) == 4
assert square(3) == 9
assert square(-2) == 4
assert square(-3) == 9
assert square(0) == 0
And then run the test with pytest test_calculator.py
$ pytest test_calculator.py
Categories of tests#
testing this code
from calculator import square
def test_positive():
assert square(2) == 4
assert square(3) == 9
def test_negative():
assert square(-2) == 4
assert square(-3) == 9
def test_zero():
assert square(0) == 0
Testing for exceptions#
testing this code
import pytest
from calculator import square
def test_positive():
assert square(2) == 4
assert square(3) == 9
def test_negative():
assert square(-2) == 4
assert square(-3) == 9
def test_zero():
assert square(0) == 0
def test_str():
with pytest.raises(TypeError):
square("cat")
Side Effects and Testing#
hello.py code#
def main():
name = input("What's your name? ")
hello(name)
def hello(to="world"):
print(f"hello, ", to)
if __name__ == "__main__":
main()
test_hello.py code#
testing this code
from hello import hello
def test_arguement():
assert hello("David") == "hello, David"
The test will fail because the function
hello
prints the message instead of returning it.Printing the message is a side effect.
Is a good practice to avoid side effects in functions as much as possible so the function can be tested.
New testable version of hello.py#
def main():
name = input("What's your name? ")
print(hello(name))
def hello(to="world"):
return f"hello, {to}"
if __name__ == "__main__":
main()
- This is a better version because the assert tests are meant to check the return value of the function and not the side effects.
test_hello.py code#
testing this code
from hello import hello
def test_default():
assert hello() == "hello, world"
def test_arguement():
for name in ["Hermione", "Harry", "Ron"]:
assert hello(name) == f"hello, {name}"
Collections of tests#
With a structure like this:
project/
hello.py
test/
__init__.py
test_hello.py
test_hello.py code#
from hello import hello
def test_default():
assert hello() == "hello, world"
def test_arguement():
assert hello("David") == "hello, David"
init.py#
Even if it’s empty, __init__.py
have the effect of telling Python that the directory is not just a module, but a package.
Running the tests#
$ pytest test