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 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||