# test_sample.py
from random import randint
from unittest.mock import patch
# from mock import patch
def get_score():
return randint(1, 10)
def pass_the_test():
score = get_score()
if score >= 6:
print("Pass")
return True
else:
print("Not Pass")
return False
# ...
# ...
@patch("test_sample.get_score")
def test_pass(mock_get_score):
mock_get_score.return_value = 8
result = pass_the_test()
assert result # assert result == True
@patch("test_sample.get_score")
def test_not_pass(mock_get_score):
mock_get_score.return_value = 2
result = pass_the_test()
assert not result # assert result == False
# test_sample.py
def double(number):
return number * 2
def test_double():
assert double(10) == 20
__init__.py
# test_sample_2.py
def add(num_1, num_2):
return num_1 + num_2
def test_add():
assert add(2, 4) == 6
# test_sample_3.py
def sub(num_1, num_2):
return num_1 - num_2
class MyMath(object):
def triple(self, number):
return number * 3
def add_five(self, number):
return number + 5
def test_sub():
assert sub(15, 3) == 12
class TestMyMath(object):
def test_triple(self):
assert MyMath().triple(10) == 30
def test_add_five(self):
assert MyMath().add_five(10) == 15
# test_sample_4.py
def say_hi(name):
print("Say Hi to {}".format(name))
return True
def test_say_hi():
assert say_hi("Maomao")
# test_sample_5.py
def always_false():
return False
def test_always_false():
assert always_false()
# my_math.py
def fibonacci(num):
if num == 0 or num == 1:
return 1
else:
return fibonacci(num-2) + fibonacci(num-1)
# test_my_math.py
from my_math import fibonacci
def test_fibonacci():
assert fibonacci(0) == 1
assert fibonacci(1) == 1
assert fibonacci(2) == 2
assert fibonacci(3) == 3
assert fibonacci(4) == 5
assert fibonacci(5) == 8
# my_math.py
def is_multiples_of_three(num):
if num % 3 == 0:
return True
else:
return False
# test_my_math.py
from my_math import is_multiples_of_three
def test_is_multiples_of_three():
# TODO: verify by 15, 23, 42, 51 and 67
pass
# my_math.py
default_cache = {
0: 1,
1: 1
}
def fibonacci(num, cache=default_cache):
if num not in cache:
if num == 0 or num == 1:
value = 1
else:
value = fibonacci(num-2, cache) + fibonacci(num-1, cache)
cache[num] = value
return cache[num]
# test_my_math.py
from my_math import fibonacci
class Testfibonacci(object):
def test_value(self):
assert fibonacci(0) == 1
assert fibonacci(1) == 1
assert fibonacci(2) == 2
assert fibonacci(3) == 3
assert fibonacci(4) == 5
assert fibonacci(5) == 8
def test_cache(self):
def _verify_result(num, cache):
for i in range(num+1):
assert i in cache
# === Case 1 ===
cache = {
0: 1,
1: 1
}
fibonacci(3, cache=cache)
_verify_result(3, cache)
# === Case 2 ===
cache = {}
fibonacci(5, cache=cache)
_verify_result(5, cache)
# my_math.py
def is_multiples_of_three(num):
if num % 3 == 0:
return True
else:
return False
def insert_number(my_list, number_list):
for num in number_list:
if is_multiples_of_three(num):
my_list.append(num)
# test_my_math.py
from my_math import insert_number
def test_insert_number():
# TODO: Case 1~6
pass
# my_math.py
default_cache = {
0: 1,
1: 1
}
def fibonacci(num, cache=default_cache):
if not isinstance(num, int) or not isinstance(cache, dict):
raise ValueError("Usage: fibonacci(num=<int>, cahce=<dict>)")
if num not in cache:
if num == 0 or num == 1:
value = 1
else:
value = fibonacci(num-2, cache) + fibonacci(num-1, cache)
cache[num] = value
return cache[num]
# test_my_math.py
from pytest import raises
from my_math import fibonacci
class Testfibonacci(object):
# ...
def test_invalid_parameter(self):
with raises(ValueError) as e:
fibonacci("123")
assert str(e.value) == "Usage: fibonacci(num=<int>, cahce=<dict>)"
with raises(ValueError) as e:
fibonacci(123, cache=[])
assert str(e.value) == "Usage: fibonacci(num=<int>, cahce=<dict>)"
with raises(...)
底下的任一行 code 一旦噴出 error,該行後的 code 將不會被執行with raises(...)
底下,因為根本不會被執行到 (UT 等於沒寫)# my_math.py
def is_multiples_of_three(num):
if not isinstance(num, int):
raise ValueError("The parameter MUST be an integer.")
if num % 3 == 0:
return True
else:
return False
# test_my_math.py
from pytest import raises
from my_math import is_multiples_of_three
def test_invalid_parameter_for_is_multiples_of_three():
# TODO
pass
>>> import mock
>>> from unittest import mock
get_today_info
回傳值,以便驗證 is_today_my_birthday
回傳值¶# about_time.py
from datetime import datetime
def get_today_info():
today = datetime.utcnow()
return today.month, today.day
def is_today_my_birthday(birthday):
month, day = get_today_info()
try:
birthday = datetime.strptime(birthday, "%m-%d")
except Exception as e:
raise ValueError(str(e))
if month == birthday.month and day == birthday.day:
return True
return False
# test_is_today_my_birthday.py
from unittest.mock import patch
# from mock import patch
from about_time import is_today_my_birthday
@patch("about_time.get_today_info")
def test_is_birthday(mock_get_today_info):
mock_get_today_info.return_value = (1, 20)
assert is_today_my_birthday("01-20")
@patch("about_time.get_today_info")
def test_is_not_birthday(mock_get_today_info):
mock_get_today_info.return_value = (10, 20)
assert not is_today_my_birthday("01-20")
# utils.py
from datetime import datetime
def get_today_info():
today = datetime.utcnow()
return today.month, today.day
# about_time.py
from datetime import datetime
from utils import get_today_info
def is_today_my_birthday(birthday):
month, day = get_today_info()
try:
birthday = datetime.strptime(birthday, "%m-%d")
except Exception as e:
raise ValueError(str(e))
if month == birthday.month and day == birthday.day:
return True
return False
# test_is_today_my_birthday.py
from unittest.mock import patch
# from mock import patch
from about_time import is_today_my_birthday
@patch("utils.get_today_info")
def test_is_birthday_candidate_1(mock_get_today_info):
mock_get_today_info.return_value = (1, 20)
assert is_today_my_birthday("01-20")
@patch("about_time.get_today_info")
def test_is_birthday_candidate_2(mock_get_today_info):
mock_get_today_info.return_value = (1, 20)
assert is_today_my_birthday("01-20")
# utils.py
from datetime import datetime
def get_today_info():
today = datetime.utcnow()
return today.month, today.day
# about_time.py
from datetime import datetime
import utils
def is_today_my_birthday(birthday):
month, day = utils.get_today_info()
try:
birthday = datetime.strptime(birthday, "%m-%d")
except Exception as e:
raise ValueError(str(e))
if month == birthday.month and day == birthday.day:
return True
return False
# test_is_today_my_birthday.py
from unittest.mock import patch
# from mock import patch
from about_time import is_today_my_birthday
@patch("utils.get_today_info")
def test_is_birthday_candidate_1(mock_get_today_info):
mock_get_today_info.return_value = (1, 20)
assert is_today_my_birthday("01-20")
@patch("about_time.utils.get_today_info")
def test_is_birthday_candidate_2(mock_get_today_info):
mock_get_today_info.return_value = (1, 20)
assert is_today_my_birthday("01-20")
get_scores_from_db
回傳值,以便驗證 grade
回傳值¶# student.py
from random import randint
def get_scores_from_db(name):
return [randint(1, 100) for i in range(3)]
def grade(name):
scores = get_scores_from_db(name)
total_score = sum(scores)
quotient = total_score // len(scores)
if quotient >= 80:
return "A"
elif quotient >= 60:
return "B"
else:
return "C"
# test_grade.py
from unittest.mock import patch
# from mock import patch
from student import grade
# TODO: test_grade_A, test_grade_B, test_grade_C
get_scores_from_db
回傳值,以便驗證 grade
回傳值¶# utils.py
from random import randint
def get_scores_from_db(name):
return [randint(1, 100) for i in range(3)]
# student.py
from utils import get_scores_from_db
def grade(name):
scores = get_scores_from_db(name)
total_score = sum(scores)
quotient = total_score // len(scores)
if quotient >= 80:
return "A"
elif quotient >= 60:
return "B"
else:
return "C"
# test_grade.py
from unittest.mock import patch
# from mock import patch
from student import grade
# TODO: test_grade_A, test_grade_B, test_grade_C
get_scores_from_db
回傳值,以便驗證 grade
回傳值¶# utils.py
from random import randint
def get_scores_from_db(name):
return [randint(1, 100) for i in range(3)]
# student.py
import utils
def grade(name):
scores = utils.get_scores_from_db(name)
total_score = sum(scores)
quotient = total_score // len(scores)
if quotient >= 80:
return "A"
elif quotient >= 60:
return "B"
else:
return "C"
# test_grade.py
from unittest.mock import patch
# from mock import patch
from student import grade
# TODO: test_grade_A, test_grade_B, test_grade_C
get_scores_from_db
¶# student.py
from random import randint
def get_scores_from_db(name):
return [randint(1, 100) for i in range(3)]
def grade(name):
scores = get_scores_from_db(name)
total_score = sum(scores)
quotient = total_score // len(scores)
if quotient >= 80:
return "A"
elif quotient >= 60:
return "B"
else:
return "C"
# test_grade.py
from unittest.mock import patch
# from mock import patch
from student import grade
@patch("student.get_scores_from_db")
def test_success_case(mock_get_scores):
mock_get_scores.return_value = [80, 90, 100]
grade("Maomao")
mock_get_scores.assert_called_once()
# assert mock_get_scores.call_count == 1
@patch("student.get_scores_from_db")
def test_failed_case(mock_get_scores):
mock_get_scores.return_value = [80, 90, 100]
grade("Maomao")
grade("Abby")
mock_get_scores.assert_called_once()
# assert mock_get_scores.call_count == 1
get_scores_from_db
且帶入的參數是正確的¶# student.py
from random import randint
def get_scores_from_db(name):
return [randint(1, 100) for i in range(3)]
def grade(name):
scores = get_scores_from_db(name)
total_score = sum(scores)
quotient = total_score // len(scores)
if quotient >= 80:
return "A"
elif quotient >= 60:
return "B"
else:
return "C"
# test_grade.py
from unittest.mock import patch
# from mock import patch
from student import grade
@patch("student.get_scores_from_db")
def test_success_case(mock_get_scores):
mock_get_scores.return_value = [80, 90, 100]
grade("Maomao")
mock_get_scores.assert_called_once_with("Maomao")
@patch("student.get_scores_from_db")
def test_failed_case(mock_get_scores):
mock_get_scores.return_value = [80, 90, 100]
grade("Maomao")
mock_get_scores.assert_called_once_with("Abby")
# party.py
def give_apple():
pass
def give_guava():
pass
def give_banana():
pass
def give_grape():
pass
def lucky_draw(color):
if color == "Red":
give_apple()
elif color == "Green":
give_guava()
elif color == "Yellow":
give_banana()
else:
give_grape()
# test_lock_draw.py
from unittest.mock import patch
# from mock import patch
from party import lucky_draw
@patch("party.give_grape")
@patch("party.give_banana")
@patch("party.give_guava")
@patch("party.give_apple")
def test_get_red_ball(mock_give_apple, mock_give_guava, mock_give_banana, mock_give_grape):
lucky_draw("Red")
mock_give_apple.assert_called_once() # assert mock_give_apple.call_count == 1
mock_give_guava.assert_not_called()
mock_give_banana.assert_not_called()
mock_give_grape.assert_not_called()
patch(...)
做 decorator 時,越下層的 decorator 產生的參數放在越前面# KFC.py
from random import randint, choice
def give_fried_chicken(number):
pass
def give_french_fries(number):
pass
def give_custard_tarts(number):
pass
def get_user_order():
return randint(1, 10), choice(["Fried chicken", "French fries", "Custard Tarts"])
def process_user_order():
number, item = get_user_order()
if item == "Fried chicken": # buy five, get one free
number += number // 5
give_fried_chicken(number)
elif item == "French fries":
give_french_fries(number)
elif item == "Custard Tarts": # buy three, get one free
number += number // 3
give_custard_tarts(number)
# test_process_user_order.py
from unittest.mock import patch
# from mock import patch
from KFC import process_user_order
# TODO:
# - test_order_two_fried_chicken, test_order_seven_fried_chicken, test_order_ten_fried_chicken
# - test_order_two_french_fries, test_order_seven_french_fries, test_order_ten_french_fries
# - test_order_two_custard_tarts, test_order_seven_custard_tarts, test_order_ten_custard_tarts
is_today_birthday
行為,使其會 raise exception,以便驗證 celebrate_for_customer
行為¶# restaurant.py
def is_today_birthday():
pass
def prepare_a_cake():
pass
def print_error(error):
pass
def celebrate_for_customer(customer_birthday):
try:
if is_today_birthday(customer_birthday):
prepare_a_cake()
except ValueError as e:
print_error(e)
# test_celebrate_for_customer.py
from unittest.mock import patch
# from mock import patch
from restaurant import celebrate_for_customer
@patch("restaurant.print_error")
@patch("restaurant.is_today_birthday")
def test_invalid_input(mock_is_today_birthday, mock_print_error):
mock_is_today_birthday.side_effect = ValueError("Invalid input")
# Otherwise, you can write like this (more powerful)
# def fake_is_today_birthday(birthday):
# raise ValueError("Invalid input")
# mock_is_today_birthday.side_effect = fake_is_today_birthday
celebrate_for_customer("01-01")
mock_print_error.assert_called_once() # assert mock_print_error.call_count == 1
cook
行為,使其會 raise exception,以便驗證 front_desk
行為¶# KFC.py
def get_order():
pass
def cook(order):
pass
def close_door():
pass
def notify_manager():
pass
def front_desk():
order = get_order()
try:
food = cook(order)
return food
except RuntimeError as e:
if "Sold Out" in str(e):
close_door()
else:
notify_manager()
# test_front_desk.py
from unittest.mock import patch
# from mock import patch
from KFC import front_desk
# TODO: test_sold_out, test_other_runtime_error
quality_checker
,以驗證 check_quality
行為是否正確¶# factory.py
class BadProductQualityError(Exception):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # For python3
# super(BadProductQuality, Exception).__init__(*args, **kwargs) # For python2
class Product():
def __init__(self, quality_checker):
self.quality_checker = quality_checker
self.color = "Red"
self.smell = "Rose"
self.length = 10
self.width = 10
self.height = 10
def create(self):
pass
def check_quality(self):
if self.quality_checker.checkpoint_1(self.length, self.width, self.height) < 95:
raise BadProductQualityError("Shape")
if self.quality_checker.checkpoint_2(self.color) < 90:
raise BadProductQualityError("Color")
if self.quality_checker.checkpoint_3(self.smell) < 98:
raise BadProductQualityError("Smell")
.<attribute_name> = <value>
.<method_name>.return_value = <value>
.<method_name>.side_effect = <exception>
.<method_name>.side_effect = <function>
.<method_name>.assert_not_called()
# test_product.py
from unittest.mock import MagicMock
# from mock import MagicMock
from pytest import raises
from factory import Product, BadProductQualityError
def test_bed_product_quality_because_of_shape():
mock_quality_checker = MagicMock()
mock_quality_checker.checkpoint_1.return_value = 94
p = Product(mock_quality_checker)
p.create()
with raises(BadProductQualityError) as e:
p.check_quality()
assert "Shape" in str(e)
def test_bed_product_quality_because_of_color():
mock_quality_checker = MagicMock()
mock_quality_checker.checkpoint_1.return_value = 95
mock_quality_checker.checkpoint_2.return_value = 89
p = Product(mock_quality_checker)
p.create()
with raises(BadProductQualityError) as e:
p.check_quality()
assert "Color" in str(e)
# ...
# ...
def test_bed_product_quality_because_of_smell():
mock_quality_checker = MagicMock()
mock_quality_checker.checkpoint_1.return_value = 95
mock_quality_checker.checkpoint_2.return_value = 90
mock_quality_checker.checkpoint_3.return_value = 97
p = Product(mock_quality_checker)
p.create()
with raises(BadProductQualityError) as e:
p.check_quality()
assert "Smell" in str(e)
def test_good_product_quality():
mock_quality_checker = MagicMock()
mock_quality_checker.checkpoint_1.return_value = 95
mock_quality_checker.checkpoint_2.return_value = 90
mock_quality_checker.checkpoint_3.return_value = 98
p = Product(mock_quality_checker)
p.create()
p.check_quality()
ProductQualityChecker
,以驗證 check_quality
行為是否正確¶# factory.py
from random import randint
class BadProductQualityError(Exception):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # For python3
# super(BadProductQuality, Exception).__init__(*args, **kwargs) # For python2
class ProductQualityChecker():
@staticmethod
def checkpoint_1(length, width, height):
return randint(1, 100)
@staticmethod
def checkpoint_2(color):
return randint(1, 100)
@staticmethod
def checkpoint_3(smell):
return randint(1, 100)
# ...
# ...
class Product():
def __init__(self):
self.color = "Red"
self.smell = "Rose"
self.length = 10
self.width = 10
self.height = 10
def create(self):
pass
def check_quality(self):
if ProductQualityChecker.checkpoint_1(self.length, self.width, self.height) < 95:
raise BadProductQualityError("Shape")
if ProductQualityChecker.checkpoint_2(self.color) < 90:
raise BadProductQualityError("Color")
if ProductQualityChecker.checkpoint_3(self.smell) < 98:
raise BadProductQualityError("Smell")
# test_product.py
from unittest.mock import patch, MagicMock
# from mock import patch, MagicMock
from pytest import raises
from factory import Product, BadProductQualityError
@patch("factory.ProductQualityChecker")
def test_bed_product_quality_because_of_shape(mock_quality_checker):
mock_quality_checker.checkpoint_1.return_value = 94
p = Product()
p.create()
with raises(BadProductQualityError) as e:
p.check_quality()
assert "Shape" in str(e)
@patch("factory.ProductQualityChecker")
def test_bed_product_quality_because_of_color(mock_quality_checker):
mock_quality_checker.checkpoint_1.return_value = 95
mock_quality_checker.checkpoint_2.return_value = 89
p = Product()
p.create()
with raises(BadProductQualityError) as e:
p.check_quality()
assert "Color" in str(e)
# ...
# ...
@patch("factory.ProductQualityChecker")
def test_bed_product_quality_because_of_smell(mock_quality_checker):
mock_quality_checker.checkpoint_1.return_value = 95
mock_quality_checker.checkpoint_2.return_value = 90
mock_quality_checker.checkpoint_3.return_value = 97
p = Product()
p.create()
with raises(BadProductQualityError) as e:
p.check_quality()
assert "Smell" in str(e)
@patch("factory.ProductQualityChecker")
def test_good_product_quality(mock_quality_checker):
mock_quality_checker.checkpoint_1.return_value = 95
mock_quality_checker.checkpoint_2.return_value = 90
mock_quality_checker.checkpoint_3.return_value = 98
p = Product()
p.create()
p.check_quality()
ProductQualityChecker
的相關方法,以驗證 check_quality
行為是否正確¶# factory.py
from random import randint
class BadProductQualityError(Exception):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) # For python3
# super(BadProductQuality, Exception).__init__(*args, **kwargs) # For python2
class ProductQualityChecker():
@staticmethod
def checkpoint_1(length, width, height):
return randint(1, 100)
@staticmethod
def checkpoint_2(color):
return randint(1, 100)
@staticmethod
def checkpoint_3(smell):
return randint(1, 100)
# ...
# ...
class Product():
def __init__(self):
self.color = "Red"
self.smell = "Rose"
self.length = 10
self.width = 10
self.height = 10
def create(self):
pass
def check_quality(self):
if ProductQualityChecker.checkpoint_1(self.length, self.width, self.height) < 95:
raise BadProductQualityError("Shape")
if ProductQualityChecker.checkpoint_2(self.color) < 90:
raise BadProductQualityError("Color")
if ProductQualityChecker.checkpoint_3(self.smell) < 98:
raise BadProductQualityError("Smell")
# test_product.py
from unittest.mock import patch
# from mock import patch
from pytest import raises
from factory import Product, BadProductQualityError
@patch("factory.ProductQualityChecker.checkpoint_1")
def test_bed_product_quality_because_of_shape(mock_checkpoint_1):
mock_checkpoint_1.return_value = 94
p = Product()
p.create()
with raises(BadProductQualityError) as e:
p.check_quality()
assert "Shape" in str(e)
@patch("factory.ProductQualityChecker.checkpoint_2")
@patch("factory.ProductQualityChecker.checkpoint_1")
def test_bed_product_quality_because_of_color(mock_checkpoint_1, mock_checkpoint_2):
mock_checkpoint_1.return_value = 95
mock_checkpoint_2.return_value = 89
p = Product()
p.create()
with raises(BadProductQualityError) as e:
p.check_quality()
assert "Color" in str(e)
# ...
# ...
@patch("factory.ProductQualityChecker.checkpoint_3")
@patch("factory.ProductQualityChecker.checkpoint_2")
@patch("factory.ProductQualityChecker.checkpoint_1")
def test_bed_product_quality_because_of_smell(mock_checkpoint_1, mock_checkpoint_2, mock_checkpoint_3):
mock_checkpoint_1.return_value = 95
mock_checkpoint_2.return_value = 90
mock_checkpoint_3.return_value = 97
p = Product()
p.create()
with raises(BadProductQualityError) as e:
p.check_quality()
assert "Smell" in str(e)
@patch("factory.ProductQualityChecker.checkpoint_3")
@patch("factory.ProductQualityChecker.checkpoint_2")
@patch("factory.ProductQualityChecker.checkpoint_1")
def test_good_product_quality(mock_checkpoint_1, mock_checkpoint_2, mock_checkpoint_3):
mock_checkpoint_1.return_value = 95
mock_checkpoint_2.return_value = 90
mock_checkpoint_3.return_value = 98
p = Product()
p.create()
p.check_quality()
get_user
回傳值,以驗證 display_user_info
行為是否正確¶# account.py
def get_user(user_id):
pass
def display_user_info(user_id):
user = get_user(user_id)
html = ""
html += "<h1>{} ({})</h1>".format(user.username, "Adult" if user.is_adult() else "Child")
return html
# test_display_user_info.py
from unittest.mock import patch, MagicMock
# from mock import patch, MagicMock
from account import display_user_info
# TODO: test_adult, test_child