Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ### Лекционная контрольная работа №1
- В данном задании вам предстоит написать свой фреймворк для unit тестирования.
- Фреймворк будет состоять из нескольких компонент:
- - Метакласс `UnitTest`
- - Декоратор `@test`
- - Декоратор `@tests_for` (БОНУСНОЕ ЗАДАНИЕ)
- #### Запуск тестов и вывод
- Метакласс `UnitTest` будет использоваться для классов, функциональность которых пользователь
- собирается тестировать.
- Декоратором `@test` помечается метод, который является отдельным test case.
- ```python
- class A(metaclass=UnitTest):
- @test
- def foo(self):
- assert False
- ```
- У метакласса `UnitTest` должен быть статический метод `run_tests`, который может быть вызван:
- - без аргументов, в этом случае должны быть запущены тесты для всех классов, созданных метаклассом `UnitTest`
- - с классом в качестве аргумента, тогда должны быть запущены тесты для переданного класса. **В случае, если переданный
- класс не является инстансом метакласса UnitTest, должно быть брошено исключение**.
- При тестировании про каждый класс должна быть выведена информация в следующем виде:
- - сначала - название класса и двоеточие
- - после - по символу на каждый тест:
- - `.` - если тест прошел успешно
- - `F` - если тест упал
- - после - трейсы по каждому падению и все, что было выведено самими тестами
- **Примечания:**
- - можно считать, что тест упал, если из него прилетел `AssertionError`; **ситуации, когда могут возникнуть
- другие исключения, обрабатывать отдельно не нужно**
- - **Во время выполнения тестов ничего не должно выводиться, т.е. нужно каким-то образом перенаправить вывод функций-тестов**
- соответственно, код ниже
- ```python
- class A(metaclass=UnitTest):
- @test
- def func1(self):
- print("Func 1 is called")
- assert 2 == 3
- print("Func 1 prints nothing after assertion")
- @test
- def func2(self):
- print("Func 2 is called")
- assert 5 == 5
- print("Func 2 after assertion")
- def func3(self):
- return True
- A()
- UnitTest.run_tests()
- ```
- должен вывести
- ```python
- <class '__main__.A'>: F.
- ____________________________________________________________________________________________________
- Func 1 is called
- Traceback (most recent call last):
- ...
- AssertionError
- ____________________________________________________________________________________________________
- Func 2 is called
- Func 2 after assertion
- ```
- #### set_up и tear_down
- Также пользователь ожидает, что наш фреймворк позволит использовать конкретный объект для тестирования с помощью
- методов `tear_down` и `set_up`:
- - метод `set_up` выполняется непосредственно перед запуском тестов, ожидается, что метод вернет экземпляр тестируемого класса.
- Все тестовые методы применяются на полученном экземпляре.
- - метод `tear_down` выполняется после выполнения всех тестов, его задача -- освободить объект, который был
- создан в `set_up`
- Конкретнее, фреймворк реализует поддержку `tear_down` и `set_up` следующим образом:
- - в метакласс в качестве ключевых аргументов `tear_down` и `set_up` могут быть переданы названия соответствующих методов
- При этом гарантируется, что оба метода будут статические и:
- - `set_up` не принимает аргументов
- - `tear_down` принимает один аргумент, который ему нужно "освободить"
- ```python
- class A(metaclass=UnitTest, set_up="create_a", tear_down="do_nothing"):
- def __init__(self, val):
- self.val = val
- @staticmethod
- def create_a():
- # создает объект, к которому будут применены тестовые методы
- return A(42)
- @staticmethod
- def do_nothing(obj):
- # *** тихонько освобождает obj ***
- pass
- @test
- def foo(self):
- # здесь self -- инстанс, который был создан с помощью create_a перед запуском тестов;
- # соответственно, эта проверка должна проходить
- assert self.val == 42
- UnitTest.run_tests(A)
- ```
- **Примечания:**
- - если `set_up` не определен, то в качестве объекта, на котором будут запускаться тесты, нужно использовать
- последний экземпляр класса
- - обрабатывать исключения, которые могли прилететь из `set_up`/`tear_down`, не нужно
- ```python
- ```python
- class A(metaclass=UnitTest):
- def __init__(self, val):
- self.val = val
- @test
- def foo(self):
- # здесь self -- последний созданный инстанс
- # соответственно, эта проверка должна проходить для кода ниже
- assert self.val == 43
- A(42)
- A(43)
- UnitTest.run_tests(A)
- ```
- #### БОНУСНОЕ ЗАДАНИЕ: tests_for
- Декоратор `@tests_for` позволяет добавлять тест-кейсы из других классов:
- ```python
- class A(metaclass=UnitTest, set_up="foo", tear_down="bar"):
- def __init__(self, val):
- self.val = val
- @staticmethod
- def foo():
- return A(42)
- @staticmethod
- def bar(x):
- return False
- @tests_for(A)
- class Tests:
- @test
- def func1(self):
- # при запуске тестов, в качестве self должен быть передан экземпляр, согданный foo, т.е. A(42)
- print("Func 1 is called")
- assert self.val == 45
- print("Func 1 prints nothing after assertion")
- @test
- def func2(self):
- # при запуске тестов, в качестве self должен быть передан экземпляр, согданный foo, т.е. A(42)
- print("Func 2 is called")
- assert self.val == 42
- print("Func 2 after assertion")
- UnitTest.run_tests()
- ```
- Обратите внимание, что в качестве `self` в методы все еще должен передаваться экземпляр, созданный `set_up`, поэтому
- код выше должен вывести следующее:
- ```
- <class '__main__.A'>: F.
- ____________________________________________________________________________________________________
- Func 1 is called
- Traceback (most recent call last):
- ...
- assert self.val == 45
- AssertionError
- ____________________________________________________________________________________________________
- Func 2 is called
- Func 2 after assertion
- ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement