Advertisement
Guest User

Untitled

a guest
Dec 14th, 2019
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.24 KB | None | 0 0
  1. ### Лекционная контрольная работа №1
  2.  
  3. В данном задании вам предстоит написать свой фреймворк для unit тестирования.
  4.  
  5. Фреймворк будет состоять из нескольких компонент:
  6. - Метакласс `UnitTest`
  7. - Декоратор `@test`
  8. - Декоратор `@tests_for` (БОНУСНОЕ ЗАДАНИЕ)
  9.  
  10. #### Запуск тестов и вывод
  11. Метакласс `UnitTest` будет использоваться для классов, функциональность которых пользователь
  12. собирается тестировать.
  13.  
  14. Декоратором `@test` помечается метод, который является отдельным test case.
  15. ```python
  16. class A(metaclass=UnitTest):
  17.     @test
  18.     def foo(self):
  19.         assert False
  20. ```
  21.  
  22. У метакласса `UnitTest` должен быть статический метод `run_tests`, который может быть вызван:
  23. - без аргументов, в этом случае должны быть запущены тесты для всех классов, созданных метаклассом `UnitTest`
  24. - с классом в качестве аргумента, тогда должны быть запущены тесты для переданного класса. **В случае, если переданный
  25. класс не является инстансом метакласса UnitTest, должно быть брошено исключение**.
  26.  
  27. При тестировании про каждый класс должна быть выведена информация в следующем виде:
  28. - сначала - название класса и двоеточие
  29. - после - по символу на каждый тест:
  30.     - `.` - если тест прошел успешно
  31.     - `F` - если тест упал
  32. - после - трейсы по каждому падению и все, что было выведено самими тестами
  33.  
  34.  
  35. **Примечания:**
  36. - можно считать, что тест упал, если из него прилетел `AssertionError`; **ситуации, когда могут возникнуть
  37.     другие исключения, обрабатывать отдельно не нужно**
  38. - **Во время выполнения тестов ничего не должно выводиться, т.е. нужно каким-то образом перенаправить вывод функций-тестов**
  39.  
  40. соответственно, код ниже
  41. ```python
  42. class A(metaclass=UnitTest):
  43.     @test
  44.     def func1(self):
  45.         print("Func 1 is called")
  46.         assert 2 == 3
  47.         print("Func 1 prints nothing after assertion")
  48.  
  49.     @test
  50.     def func2(self):
  51.         print("Func 2 is called")
  52.         assert 5 == 5
  53.         print("Func 2 after assertion")
  54.  
  55.     def func3(self):
  56.         return True
  57. A()
  58. UnitTest.run_tests()
  59. ```
  60.  
  61. должен вывести
  62. ```python
  63. <class '__main__.A'>: F.
  64.  
  65. ____________________________________________________________________________________________________
  66.  
  67. Func 1 is called
  68.  
  69. Traceback (most recent call last):
  70.   ...
  71. AssertionError
  72.  
  73. ____________________________________________________________________________________________________
  74.  
  75. Func 2 is called
  76. Func 2 after assertion
  77. ```
  78.  
  79. #### set_up и tear_down
  80. Также пользователь ожидает, что наш фреймворк позволит использовать конкретный объект для тестирования с помощью
  81. методов `tear_down` и `set_up`:
  82. - метод `set_up` выполняется непосредственно перед запуском тестов, ожидается, что метод вернет экземпляр тестируемого класса.
  83. Все тестовые методы применяются на полученном экземпляре.  
  84. - метод `tear_down` выполняется после выполнения всех тестов, его задача -- освободить объект, который был
  85. создан в `set_up`
  86.  
  87. Конкретнее, фреймворк реализует поддержку `tear_down` и `set_up` следующим образом:
  88. - в метакласс в качестве ключевых аргументов `tear_down` и `set_up` могут быть переданы названия соответствующих методов
  89.  
  90. При этом гарантируется, что оба метода будут статические и:
  91. - `set_up` не принимает аргументов
  92. - `tear_down` принимает один аргумент, который ему нужно "освободить"
  93.  
  94. ```python
  95. class A(metaclass=UnitTest, set_up="create_a", tear_down="do_nothing"):
  96.     def __init__(self, val):
  97.         self.val = val
  98.    
  99.     @staticmethod
  100.     def create_a():
  101.         # создает объект, к которому будут применены тестовые методы
  102.         return A(42)
  103.  
  104.     @staticmethod
  105.     def do_nothing(obj):
  106.         # *** тихонько освобождает obj ***
  107.         pass
  108.  
  109.     @test
  110.     def foo(self):
  111.         # здесь self -- инстанс, который был создан с помощью create_a перед запуском тестов;
  112.         # соответственно, эта проверка должна проходить
  113.         assert self.val == 42
  114.  
  115. UnitTest.run_tests(A)
  116. ```
  117.  
  118.  **Примечания:**
  119.  - если `set_up` не определен, то в качестве объекта, на котором будут запускаться тесты, нужно использовать
  120.  последний экземпляр класса
  121.  - обрабатывать исключения, которые могли прилететь из `set_up`/`tear_down`, не нужно
  122.  ```python
  123. ```python
  124. class A(metaclass=UnitTest):
  125.     def __init__(self, val):
  126.         self.val = val
  127.    
  128.     @test
  129.     def foo(self):
  130.         # здесь self -- последний созданный инстанс
  131.         # соответственно, эта проверка должна проходить для кода ниже
  132.         assert self.val == 43
  133.  
  134. A(42)
  135. A(43)
  136.  
  137. UnitTest.run_tests(A)
  138. ```
  139. #### БОНУСНОЕ ЗАДАНИЕ: tests_for
  140. Декоратор `@tests_for` позволяет добавлять тест-кейсы из других классов:
  141. ```python
  142. class A(metaclass=UnitTest, set_up="foo", tear_down="bar"):
  143.     def __init__(self, val):
  144.         self.val = val
  145.  
  146.     @staticmethod
  147.     def foo():
  148.         return A(42)
  149.  
  150.     @staticmethod
  151.     def bar(x):
  152.         return False
  153.  
  154. @tests_for(A)
  155. class Tests:
  156.     @test
  157.     def func1(self):
  158.         # при запуске тестов, в качестве self должен быть передан экземпляр, согданный foo, т.е. A(42)
  159.         print("Func 1 is called")
  160.         assert self.val == 45
  161.         print("Func 1 prints nothing after assertion")
  162.  
  163.     @test
  164.     def func2(self):
  165.         # при запуске тестов, в качестве self должен быть передан экземпляр, согданный foo, т.е. A(42)
  166.         print("Func 2 is called")
  167.         assert self.val == 42
  168.         print("Func 2 after assertion")
  169.  
  170. UnitTest.run_tests()
  171. ```
  172.  
  173. Обратите внимание, что в качестве `self` в методы все еще должен передаваться экземпляр, созданный `set_up`, поэтому
  174. код выше должен вывести следующее:
  175. ```
  176. <class '__main__.A'>: F.
  177.  
  178. ____________________________________________________________________________________________________
  179.  
  180. Func 1 is called
  181.  
  182. Traceback (most recent call last):
  183.   ...
  184.     assert self.val == 45
  185. AssertionError
  186.  
  187. ____________________________________________________________________________________________________
  188.  
  189. Func 2 is called
  190. Func 2 after assertion
  191.  
  192. ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement