CS50P 5_Unit Test
Why Test?
A function needs to ensure it is well-designed.
Function Test by print()
def main():
# test combine_str()
combine_str("東華","大學")
def combine_str(str1, str2):
"""
合併兩個字串:
Args: str1 (str): 字串 1
str2 (str): 字串 2
print str: str1 + str2
"""
print(str1 + str2)
main()
$ python strTool_1.py
東華大學
strTool_1.py
Function Test Based on Return Value
def main():
# test combine_str()
print(combine_str("東華","大學"))
def combine_str(str1, str2):
"""
合併兩個字串:
Args: str1 (str): 字串 1
str2 (str): 字串 2
Returns: str: str1 + str2
"""
return(str1 + str2)
main()
$ python strTool_2.py
東華大學
strTool_2.py
Function to be Used
def main():
# test combine_str()
print(combine_str("東華","大學"))
def combine_str(str1, str2):
return(str1 + str2)
if __name__ == "__main__":
main()
$ python strTool.py
東華大學
strTool.py
Using the strTool function with import package
import strTool
print(strTool.combine_str("測試 ","Combine_str"))
$ python strTool_use_1.py
測試 Combine_str
strTool_use_1.py
import strTool as st
print(st.combine_str("測試 ","Combine_str"))
$ strTool_use_2.py
測試 Combine_str
strTool_use_2.py
Using the strTool function with a package alias
strTool_use_3.py
from strTool import combine_str
print(combine_str("測試 ","Combine_str"))
$ strTool_use_3.py
測試 Combine_str
Using the strTool function with
import package method
Python Test Framework
Many Functions, Many Tests?
Pytest is a fully-featured, mature Python testing tool that helps you write better programs.
MathTool Square Function
def main():
print(f"square of 3 is {square(3)}")
def square(num):
"""回傳平方值
Args:
num (int): 數值
Returns:
int: 平方後的數值
"""
return num**2
if __name__ == "__main__":
main()
$ python mathTool.py
square of 3 is 9
mathTool.py
MathTool: Test the Square Function
def main():
test_square()
def test_square():
if square(2) == 4:
print(f"square of 2 is 4")
if square(3) == 9:
print(f"square of 3 is 9")
def square(num):
return num**2
if __name__ == "__main__":
main()
$ python mathTool_test.py
square of 2 is 4
square of 3 is 9
mathTool_test.py
Function Test Problem
- How many numbers need to be tested?
- How many tests pass?
- How many tests fail?
Assert
If your code returns True, nothing happens.
If your code returns False, an AssertionError is raised.
assert condition, error_message
Example of Assertion
x = "hello"
print(f"x = {x}")
print("======================")
#if condition returns True, then nothing happens
print('assert x == "hello"') #test True
assert x == "hello", "x should be 'hello'"
print("======================")
#if condition returns False, AssertionError is raised
print('assert x == "goodbye"') #test Fail
assert x == "goodbye", "x should be 'hello'"
$ python assert.py
x = hello
======================
assert x == "hello"
======================
assert x == "goodbye"
Traceback (most recent call last):
File "/workspaces/87635444/test/unit_test/assert.py", line 12, in <module>
assert x == "goodbye", "x should be 'hello'"
^^^^^^^^^^^^^^
assert.py
Square Function Test Using Assert
from mathTool import square
def main():
test_square()
def test_square():
assert square(3) == 9
assert square(1) == 4, "一的平方是一"
if __name__ == "__main__":
main()
test/unit_test/ $ python mathTool_assert.py
Traceback (most recent call last):
File "/workspaces/87635444/test/unit_test/mathTool_assert.py", line 11, in <module>
main()
File "/workspaces/87635444/test/unit_test/mathTool_assert.py", line 4, in main
test_square()
File "/workspaces/87635444/test/unit_test/mathTool_assert.py", line 8, in test_square
assert square(1) == 4, "一的平方是一"
^^^^^^^^^^^^^^
AssertionError: 一的平方是一
mathTool_assert.py
pytest
File Name : testxxxx.py
Function : testxxx
Pytest Example: Pass
from mathTool import square
def main():
test_square()
def test_square():
assert square(1) == 1
assert square(3) == 9
if __name__ == "__main__":
main()
test_math_pass.py
$ pytest
============================================= test session starts ==============================================
platform linux -- Python 3.10.7, pytest-7.1.3, pluggy-1.0.0
rootdir: /workspaces/87635444/test/unit_test
collected 1 item
test_math_pass.py . [100%]
============================================== 1 passed in 0.01s ===============================================
Pytest Example: Failed
from mathTool import square
def main():
test_square()
def test_square():
assert square(1) == 2 # assert error
assert square(3) == 9
if __name__ == "__main__":
main()
test_math_fail.py
Pytest Fail Result
$ pytest test_math_fail.py
============================================= test session starts ==============================================
platform linux -- Python 3.10.7, pytest-7.1.3, pluggy-1.0.0
rootdir: /workspaces/87635444/test/unit_test
collected 1 item
test_math_fail.py F [100%]
=================================================== FAILURES ===================================================
_________________________________________________ test_square __________________________________________________
def test_square():
> assert square(1) == 2
E assert 1 == 2
E + where 1 = square(1)
test_math_fail.py:7: AssertionError
=========================================== short test summary info ============================================
FAILED test_math_fail.py::test_square - assert 1 == 2
============================================== 1 failed in 0.09s ===============================================
Catch AssertionError
from mathTool import square
def main():
test_square()
def test_square():
try:
assert square(1) == 2
except AssertionError:
print("1的平方不是2")
try:
assert square(3) == 9
except AssertionError:
print("3的平方不是9")
if __name__ == "__main__":
main()
python catch_assert_error.py
1的平方不是2
catch_assert_error.py
Pytest Pass
While the AssertionError was caught, pytrst passes.
pytest catch_assert_error.py
============================================= test session starts ==============================================
platform linux -- Python 3.10.7, pytest-7.1.3, pluggy-1.0.0
rootdir: /workspaces/87635444/test/unit_test
collected 1 item
catch_assert_error.py . [100%]
============================================== 1 passed in 0.01s ===============================================
Multiple Assert
from mathTool import square
def main():
test_square()
def test_square():
assert square(2) == 4
assert square(3) == 9
assert square(-2) == 4
assert square(-3) == 9
assert square(0) == 0
if __name__ == "__main__":
main()
multiple_assert.py
Multiple Assert Pytest Pass
pytest multiple_assert.py
============================================= test session starts ==============================================
platform linux -- Python 3.10.7, pytest-7.1.3, pluggy-1.0.0
rootdir: /workspaces/87635444/test/unit_test
collected 1 item
multiple_assert.py . [100%]
============================================== 1 passed in 0.01s ===============================================
Different Test Method
from mathTool import square
def main():
test_square()
def test_positive():
assert square(1) == 2 # erroe 1 != 2
assert square(2) == 4
assert square(3) == 9
def test_negative():
assert square(-1) == 1
assert square(-2) == 4
assert square(-3) == 9
def test_zero():
assert square(0) == 0
if __name__ == "__main__":
main()
different_test.py
Different Test Method Fail.
$ pytest different_test.py
============================================= test session starts ==============================================
platform linux -- Python 3.10.7, pytest-7.1.3, pluggy-1.0.0
rootdir: /workspaces/87635444/test/unit_test
collected 3 items
different_test.py F.. [100%]
=================================================== FAILURES ===================================================
________________________________________________ test_positive _________________________________________________
def test_positive():
> assert square(1) == 2
E assert 1 == 2
E + where 1 = square(1)
different_test.py:7: AssertionError
=========================================== short test summary info ============================================
FAILED different_test.py::test_positive - assert 1 == 2
========================================= 1 failed, 2 passed in 0.08s ==========================================
test/unit_test/ $
Function has an error
def main():
square("aaa")
def square(num):
return num**2
if __name__ == "__main__":
main()
python math_tool.py
Traceback (most recent call last):
File "/workspaces/87635444/test/unit_test/math_tool.py", line 8, in <module>
main()
File "/workspaces/87635444/test/unit_test/math_tool.py", line 2, in main
square("aaa")
File "/workspaces/87635444/test/unit_test/math_tool.py", line 5, in square
return num**2
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
math_tool.py
Error in assert method - getting error
from mathTool import square
import pytest
def main():
test_square()
def test_positive():
assert square(1) == 1
assert square(2) == 4
assert square(3) == 9
def test_str():
assert square("cat") # will raise TypeError
if __name__ == "__main__":
main()
math_tool_error.py
Pytest: Troubleshooting Errors and Failures
pytest math_tool_error.py
============================================= test session starts ==============================================
platform linux -- Python 3.10.7, pytest-7.1.3, pluggy-1.0.0
rootdir: /workspaces/87635444/test/unit_test
collected 2 items
math_tool_error.py .F [100%]
=================================================== FAILURES ===================================================
___________________________________________________ test_str ___________________________________________________
def test_str():
> assert square("cat")
math_tool_error.py:13:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
num = 'cat'
def square(num):
> return num**2
E TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
math_tool_error.py:5: TypeError
=========================================== short test summary info ============================================
FAILED math_tool_error.py::test_str - TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
========================================= 1 failed, 1 passed in 0.14s ==========================================
Pytest: Catching Expected Custom Error
from mathTool import square
import pytest
def main():
test_square()
def test_positive():
assert square(1) == 1
assert square(2) == 4
assert square(3) == 9
def test_str():
with pytest.raises(TypeError):
assert square("cat") # will raise TypeError
if __name__ == "__main__":
main()
catch_error.py
Pass: pytest catches expected custom error
$ pytest catch_error.py
============================================= test session starts ==============================================
platform linux -- Python 3.10.7, pytest-7.1.3, pluggy-1.0.0
rootdir: /workspaces/87635444/test/unit_test
collected 2 items
catch_error.py .. [100%]
============================================== 2 passed in 0.01s ===============================================
Function with Default Value
def main():
print(hello())
print(hello("Ted"))
def hello(to="world"):
return f"hello, {to}"
if __name__ == "__main__":
main()
$ python hello.py
hello, world
hello, Ted
hello.py
Test Hello with Default Value and List
from hello import hello
def test_default():
assert hello() == "hello, world"
def test_argument():
assert hello("David") == "hello, David"
def test_arguments():
for name in ["Hermione", "Harry", "Ron"]:
assert hello(name) == f"hello, {name}"
test_hello.py
Pytest test_hello.py: PASS
$ pytest test_hello.py
============================================= test session starts ==============================================
platform linux -- Python 3.10.7, pytest-7.1.3, pluggy-1.0.0
rootdir: /workspaces/87635444/test/unit_test
collected 3 items
test_hello.py ... [100%]
============================================== 3 passed in 0.01s ===============================================
CS50P 5_Unit Test
By wschen
CS50P 5_Unit Test
CS50P 5_Unit Test presentation covers the importance of testing in programming, different testing methods, and the use of Python test frameworks like pytest. It also showcases examples of successful and failed tests, along with handling errors and assertions.
- 135