1import unittest
2from unittest.mock import mock_open, patch
3
4from secret import validate_recipe, RuinedNikuldenDinnerError
5
6
7class TestNikuldenValidator(unittest.TestCase):
8 def test_valid_recipe(self):
9 valid_cases = [
10 "Тази рецепта съдържа риба.",
11 "Запечете рибена глава.",
12 "На Никулден се приготвя шаран..",
13 "Сьонга е за печене.",
14 "РИБА на фурна.",
15 "арфтцрь56всра%€§$%§ риба.",
16 "РиБа с ориз."
17 ]
18 for content in valid_cases:
19 with patch("builtins.open", mock_open(read_data=content)):
20 self.assertTrue(validate_recipe("valid_recipe.txt"))
21
22 def test_invalid_recipe(self):
23 invalid_cases = [
24 "Днес ще готвим пилешко.",
25 " Днес има ориз.",
26 "Само зеленчуци ириба.",
27 "рибено масло и картофи.",
28 "€§*€%§*(()",
29 ""
30 ]
31 for content in invalid_cases:
32 with patch("builtins.open", mock_open(read_data=content)):
33 self.assertFalse(validate_recipe("invalid_recipe.txt"))
34
35 def test_bad_recipe_file(self):
36 with patch("builtins.open", side_effect=OSError):
37 with self.assertRaises(RuinedNikuldenDinnerError):
38 validate_recipe("bad_recipe.txt")
39
40
41if __name__ == "__main__":
42 unittest.main()
....
----------------------------------------------------------------------
Ran 4 tests in 0.074s
OK
Виктор Бечев
07.12.2024 12:57Можеш да напишеш нещо сравнително кратко, което да ти прави въпросните пермутации, но истината е, че не е нужно.
Алтернативен пример - ако имаме функция, която повдига четни числа на втора степен, нечетни - на трета и работи в отворен интервал от 0 до 100. Имаме да тестване за:
1. Четно число.
2. Нечетно число.
3. Гранични стойности - 0 и 100.
Не е нужно да тестваме с 2, 4, 6, 8 и т.н., достатъчно е да тестваме с едно четно число. Същото важи и за нечетните. Не е нужно да тестваме и за -5 и -500, достатъчно е да изтестваме поведението в граничните стойности - 0 и 100.
Философията тук е, че да, винаги можеш да напишеш функция, която се чупи точно на 87. Но идеята не е да тестваме функциите, които пишем с всеки възможен input, а да генерализираме тестовете си спрямо изискванията, така че да могат да ни дадат достатъчно добра увереност, че функцията изпълнява дефинираните изисквания. Защото този проблем, който дефинирах е с елементарна сложност, но ако функцията ти е по-сложна или дори със същата сложност, но има граници от -сто милиона до +сто милиона - ще тестваш ли 200 000 002 пъти? Пък и да не забравяме невалидните стойности - те са безкрайно множество.
Така че - тестовете ти са чудесни, хванала си дори и случая `"Само зеленчуци ириба."`. Повече от това не е необходимо.
|
Ева Ганчева
06.12.2024 14:08Исках да попитам също дали има по-умен начин да се направят тестовете, така че да тестват повече функционалности, например предполагам може с f string и вътре да има ключовите думи, но как мога да генерирам всички разновидности на риба - тоест рИба, риБа .... Просто се чудех дали има функция, която го прави
|
f | 1 | import unittest | f | 1 | import unittest |
2 | from unittest.mock import mock_open, patch | 2 | from unittest.mock import mock_open, patch | ||
3 | 3 | ||||
4 | from secret import validate_recipe, RuinedNikuldenDinnerError | 4 | from secret import validate_recipe, RuinedNikuldenDinnerError | ||
5 | 5 | ||||
6 | 6 | ||||
7 | class TestNikuldenValidator(unittest.TestCase): | 7 | class TestNikuldenValidator(unittest.TestCase): | ||
8 | def test_valid_recipe(self): | 8 | def test_valid_recipe(self): | ||
9 | valid_cases = [ | 9 | valid_cases = [ | ||
10 | "Тази рецепта съдържа риба.", | 10 | "Тази рецепта съдържа риба.", | ||
11 | "Запечете рибена глава.", | 11 | "Запечете рибена глава.", | ||
12 | "На Никулден се приготвя шаран..", | 12 | "На Никулден се приготвя шаран..", | ||
13 | "Сьонга е за печене.", | 13 | "Сьонга е за печене.", | ||
14 | "РИБА на фурна.", | 14 | "РИБА на фурна.", | ||
15 | "арфтцрь56всра%€§$%§ риба.", | 15 | "арфтцрь56всра%€§$%§ риба.", | ||
16 | "РиБа с ориз." | 16 | "РиБа с ориз." | ||
17 | ] | 17 | ] | ||
18 | for content in valid_cases: | 18 | for content in valid_cases: | ||
19 | with patch("builtins.open", mock_open(read_data=content)): | 19 | with patch("builtins.open", mock_open(read_data=content)): | ||
20 | self.assertTrue(validate_recipe("valid_recipe.txt")) | 20 | self.assertTrue(validate_recipe("valid_recipe.txt")) | ||
21 | 21 | ||||
22 | def test_invalid_recipe(self): | 22 | def test_invalid_recipe(self): | ||
23 | invalid_cases = [ | 23 | invalid_cases = [ | ||
24 | "Днес ще готвим пилешко.", | 24 | "Днес ще готвим пилешко.", | ||
25 | " Днес има ориз.", | 25 | " Днес има ориз.", | ||
t | 26 | "Само зеленчуци и риба.", | t | 26 | "Само зеленчуци ириба.", |
27 | "рибено масло и картофи.", | 27 | "рибено масло и картофи.", | ||
28 | "€§*€%§*(()", | 28 | "€§*€%§*(()", | ||
29 | "" | 29 | "" | ||
30 | ] | 30 | ] | ||
31 | for content in invalid_cases: | 31 | for content in invalid_cases: | ||
32 | with patch("builtins.open", mock_open(read_data=content)): | 32 | with patch("builtins.open", mock_open(read_data=content)): | ||
33 | self.assertFalse(validate_recipe("invalid_recipe.txt")) | 33 | self.assertFalse(validate_recipe("invalid_recipe.txt")) | ||
34 | 34 | ||||
35 | def test_bad_recipe_file(self): | 35 | def test_bad_recipe_file(self): | ||
36 | with patch("builtins.open", side_effect=OSError): | 36 | with patch("builtins.open", side_effect=OSError): | ||
37 | with self.assertRaises(RuinedNikuldenDinnerError): | 37 | with self.assertRaises(RuinedNikuldenDinnerError): | ||
38 | validate_recipe("bad_recipe.txt") | 38 | validate_recipe("bad_recipe.txt") | ||
39 | 39 | ||||
40 | 40 | ||||
41 | if __name__ == "__main__": | 41 | if __name__ == "__main__": | ||
42 | unittest.main() | 42 | unittest.main() |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | import unittest | f | 1 | import unittest |
2 | from unittest.mock import mock_open, patch | 2 | from unittest.mock import mock_open, patch | ||
3 | 3 | ||||
4 | from secret import validate_recipe, RuinedNikuldenDinnerError | 4 | from secret import validate_recipe, RuinedNikuldenDinnerError | ||
5 | 5 | ||||
6 | 6 | ||||
7 | class TestNikuldenValidator(unittest.TestCase): | 7 | class TestNikuldenValidator(unittest.TestCase): | ||
8 | def test_valid_recipe(self): | 8 | def test_valid_recipe(self): | ||
9 | valid_cases = [ | 9 | valid_cases = [ | ||
10 | "Тази рецепта съдържа риба.", | 10 | "Тази рецепта съдържа риба.", | ||
11 | "Запечете рибена глава.", | 11 | "Запечете рибена глава.", | ||
n | 12 | "На Никулден се приготвя шаран.", | n | 12 | "На Никулден се приготвя шаран..", |
13 | "Сьонга е за печене.", | 13 | "Сьонга е за печене.", | ||
14 | "РИБА на фурна.", | 14 | "РИБА на фурна.", | ||
15 | "арфтцрь56всра%€§$%§ риба.", | 15 | "арфтцрь56всра%€§$%§ риба.", | ||
16 | "РиБа с ориз." | 16 | "РиБа с ориз." | ||
17 | ] | 17 | ] | ||
18 | for content in valid_cases: | 18 | for content in valid_cases: | ||
19 | with patch("builtins.open", mock_open(read_data=content)): | 19 | with patch("builtins.open", mock_open(read_data=content)): | ||
20 | self.assertTrue(validate_recipe("valid_recipe.txt")) | 20 | self.assertTrue(validate_recipe("valid_recipe.txt")) | ||
21 | 21 | ||||
22 | def test_invalid_recipe(self): | 22 | def test_invalid_recipe(self): | ||
23 | invalid_cases = [ | 23 | invalid_cases = [ | ||
n | 24 | "Днес ще готвим пилешко месо.", | n | 24 | "Днес ще готвим пилешко.", |
25 | " Днес има ориз.", | ||||
25 | "Само зеленчуци ириба.", | 26 | "Само зеленчуци и риба.", | ||
26 | "рибено масло и картофи.", | 27 | "рибено масло и картофи.", | ||
t | 27 | "!@#$%^&*()", | t | 28 | "€§*€%§*(()", |
28 | "" | 29 | "" | ||
29 | ] | 30 | ] | ||
30 | for content in invalid_cases: | 31 | for content in invalid_cases: | ||
31 | with patch("builtins.open", mock_open(read_data=content)): | 32 | with patch("builtins.open", mock_open(read_data=content)): | ||
32 | self.assertFalse(validate_recipe("invalid_recipe.txt")) | 33 | self.assertFalse(validate_recipe("invalid_recipe.txt")) | ||
33 | 34 | ||||
34 | def test_bad_recipe_file(self): | 35 | def test_bad_recipe_file(self): | ||
35 | with patch("builtins.open", side_effect=OSError): | 36 | with patch("builtins.open", side_effect=OSError): | ||
36 | with self.assertRaises(RuinedNikuldenDinnerError): | 37 | with self.assertRaises(RuinedNikuldenDinnerError): | ||
37 | validate_recipe("bad_recipe.txt") | 38 | validate_recipe("bad_recipe.txt") | ||
38 | 39 | ||||
39 | 40 | ||||
40 | if __name__ == "__main__": | 41 | if __name__ == "__main__": | ||
41 | unittest.main() | 42 | unittest.main() |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
f | 1 | import unittest | f | 1 | import unittest |
2 | from unittest.mock import mock_open, patch | 2 | from unittest.mock import mock_open, patch | ||
n | n | 3 | |||
3 | from secret import validate_recipe, RuinedNikuldenDinnerError | 4 | from secret import validate_recipe, RuinedNikuldenDinnerError | ||
n | n | 5 | |||
4 | 6 | ||||
5 | class TestNikuldenValidator(unittest.TestCase): | 7 | class TestNikuldenValidator(unittest.TestCase): | ||
6 | def test_valid_recipe(self): | 8 | def test_valid_recipe(self): | ||
7 | valid_cases = [ | 9 | valid_cases = [ | ||
8 | "Тази рецепта съдържа риба.", | 10 | "Тази рецепта съдържа риба.", | ||
9 | "Запечете рибена глава.", | 11 | "Запечете рибена глава.", | ||
10 | "На Никулден се приготвя шаран.", | 12 | "На Никулден се приготвя шаран.", | ||
11 | "Сьонга е за печене.", | 13 | "Сьонга е за печене.", | ||
12 | "РИБА на фурна.", | 14 | "РИБА на фурна.", | ||
13 | "арфтцрь56всра%€§$%§ риба.", | 15 | "арфтцрь56всра%€§$%§ риба.", | ||
14 | "РиБа с ориз." | 16 | "РиБа с ориз." | ||
15 | ] | 17 | ] | ||
16 | for content in valid_cases: | 18 | for content in valid_cases: | ||
17 | with patch("builtins.open", mock_open(read_data=content)): | 19 | with patch("builtins.open", mock_open(read_data=content)): | ||
18 | self.assertTrue(validate_recipe("valid_recipe.txt")) | 20 | self.assertTrue(validate_recipe("valid_recipe.txt")) | ||
n | n | 21 | |||
19 | def test_invalid_recipe(self): | 22 | def test_invalid_recipe(self): | ||
20 | invalid_cases = [ | 23 | invalid_cases = [ | ||
21 | "Днес ще готвим пилешко месо.", | 24 | "Днес ще готвим пилешко месо.", | ||
22 | "Само зеленчуци ириба.", | 25 | "Само зеленчуци ириба.", | ||
23 | "рибено масло и картофи.", | 26 | "рибено масло и картофи.", | ||
24 | "!@#$%^&*()", | 27 | "!@#$%^&*()", | ||
25 | "" | 28 | "" | ||
26 | ] | 29 | ] | ||
27 | for content in invalid_cases: | 30 | for content in invalid_cases: | ||
28 | with patch("builtins.open", mock_open(read_data=content)): | 31 | with patch("builtins.open", mock_open(read_data=content)): | ||
29 | self.assertFalse(validate_recipe("invalid_recipe.txt")) | 32 | self.assertFalse(validate_recipe("invalid_recipe.txt")) | ||
n | n | 33 | |||
30 | def test_bad_recipe_file(self): | 34 | def test_bad_recipe_file(self): | ||
31 | with patch("builtins.open", side_effect=OSError): | 35 | with patch("builtins.open", side_effect=OSError): | ||
32 | with self.assertRaises(RuinedNikuldenDinnerError): | 36 | with self.assertRaises(RuinedNikuldenDinnerError): | ||
33 | validate_recipe("bad_recipe.txt") | 37 | validate_recipe("bad_recipe.txt") | ||
34 | 38 | ||||
t | t | 39 | |||
35 | if __name__ == "__main__": | 40 | if __name__ == "__main__": | ||
36 | unittest.main() | 41 | unittest.main() |
Legends | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
|