Я начал изучать Selenium, и мне любопытно, как реализовать поведение класса PythonOrgSearch
, который наследуется от unittest.TestCase
. А именно, каждый метод, который начинается с test_
, будет вызываться автоматически после инициализации. Я знаю, что это поведение реализовано в TestCase
, но мне интересно, как сделать что-то похожее. Есть ли шаблон дизайна, который позаботится об этом?
И еще один бонусный вопрос, какой смысл assert True
, так как условие всегда True
import unittest
from selenium import webdriver
class PythonOrgSearch(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome("C:\chorme\chromedriver.exe")
self.driver.get("http://www.python.org")
def test_example(self):
print("Test")
assert True
def not_test(self):
print("Not a test")
def tearDown(self):
self.driver.close()
if __name__ == "__main__":
unittest.main()
3 ответа
Вы можете делать то, что хотите, с метаклассом, который может настраивать построение ваших собственных классов. Это очень мощная и общая техника и, возможно, шаблон проектирования Python.
Ниже приведен пример его применения к тому, что вы хотите сделать. Метод метакласса __new__()
просматривает содержимое определяемого класса - когда он вызывается - и ищет вызываемые атрибуты, имена которых начинаются с test_
. После этого он определяет методы __init__()
и post_init()
и делает их частью класса. Первый вызывает последний метод, который затем итеративно вызывает все определенные методы, которые имеют совпадающие имена.
class MyMetaClass(type):
""" Create class that calls an added post_init() method which in turn calls
all method's whose names start with "test_".
"""
def __new__(meta, classname, bases, classdict):
# Get any class __init__() method defined.
class_init = classdict.get('__init__', lambda *_, **__: None)
test_funcs = [value for key, value in classdict.items()
if key.startswith('test_') and callable(value)]
def __init__(self, *args, **kwargs):
print('In metaclass generated __init__()')
class_init(self, *args, **kwargs) # Call class' __init__() method.
self.post_init()
def post_init(self):
print('In metaclass generated post_init()')
for method in test_funcs:
print(f'calling {classname}.{method.__name__}()')
method(self)
classdict.update({'__init__': __init__, # Attach methods to class.
'post_init': post_init})
return type.__new__(meta, classname, bases, classdict)
class Example(metaclass=MyMetaClass):
def __init__(self, arg, macnab=None):
print(f'in Example.__init__({arg!r}, macnab={macnab!r})')
def setUp(self):
pass
def test_example1(self):
print("Test1")
def test_example2(self):
print("Test2")
def not_test(self):
print("Not a test")
def tearDown(self):
print("Also not a test")
pass
print('Creating instance of Example')
Example = Example(42, macnab='keyword')
Выход:
Creating instance of Example
In metaclass generated __init__()
in Example.__init__(42, macnab='keyword')
In metaclass generated post_init()
calling Example.test_example1()
Test1
calling Example.test_example2()
Test2
По первому вопросу вы можете использовать dir()
в self
, чтобы получить список его членов (Полезная документация для dir).
После этого вы можете протестировать шаблон имени простым способом, и, если он вызывается, вы можете вызвать его:
for name in dir(self):
if name[:5] == 'test_' and callable(getattr(self, name)):
res = getattr(self, name)()
print(res)
Что касается вашего бонусного вопроса, то обычно вынуждают перегружать функцию.
Я бы предположил, что они просто находят вызываемые методы, которые начинаются с «test_» с использованием функции dir()
. То, что вы могли бы достичь довольно легко, как:
class CustomTestCaseRunner:
def run(self):
methods = [
m for m in dir(self)
if callable(getattr(self, m))
and m.startswith("test_")
]
for m in methods:
print(f"Running {self.__class__.__name__}.{m}")
getattr(self, m)()
class MyTest(CustomTestCaseRunner):
def test_foo(self):
assert True
def test_bar(self):
assert 1
MyTest().run()
# Running MyTest.test_bar
# Running MyTest.test_foo
Что касается вашего второго вопроса о assert True
, маловероятно, что вы когда-либо действительно assert True
в реальном коде. Эта функция, кажется, просто пример. assert
обычно используется в ответе от функции. Вот несколько примеров:
assert isinstance(1, int)
assert isinstance("foo", str)
Когда условие оценивается как False
, оно вызовет AssertionError
, что не пройдёт ваш тестовый пример.
Похожие вопросы
Новые вопросы
python
Python — это мультипарадигмальный многоцелевой язык программирования с динамической типизацией. Он предназначен для быстрого изучения, понимания и использования, а также обеспечивает чистый и унифицированный синтаксис. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Если у вас есть вопросы о версии Python, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas, NumPy) укажите это в тегах.