Вчера на работе, один из ребят из команды контроля качества подошел ко мне с вопросом, который оказался намного интереснее для меня, чем он изначально планировал (я так думаю). Он проводил тестирование элементов, используя Selenium, экспортируя тестовые случаи в Python. Итак, вопросом, который он задал, было: как я могу проганять один и тот же юнит тест для нескольких браузеров и нескольких целевых серверов?
Я просто уверен, что он ожидал получить простой ответ с алгоритмом из трех шагов, или что-то вроде этого. Вместо этого он увидел мои сумасшедшие глаза и вид, говорящий "оооо… это то, с чем я хочу поэкспериментировать!". Я начал молоть какой-то вздор о наследовании свойств, динамическом создании классов и продолжал «петлять» дальше. В его глазах появилось беспокойство. На самом деле ему не слишком понравились мои заумные рассказы. Я сказал ему присаживаться в кресло и устраиваться поудобнее.
Так как у меня уже была некоторая работа, которую необходимо было сделать, мне не хотелось тратить много времени на поиски оптимального способа решения этой проблемы. Через 20 минут поисков в документации по Python я пришел к следующему коду:
from types import ClassType
from selenium import selenium
import unittest
IPS = ['192.168.0.1', '192.168.0.2']
BROWSERS = ['safari', 'chrome']
class SomeUnitTest(object):
def test_something(self):
sel = self.selenium
# test code
def main(base):
suites = []
results = unittest.TestResult()
for iidx, ip in enumerate(IPS):
for bidx, browser in enumerate(BROWSERS):
def setUp(self):
self.verificationErrors = []
self.selenium = selenium("localhost", 4444, "*%s" % self.browser, "http://%s/" % self.ip)
self.selenium.start()
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
ut = ClassType('UT_%i_%i' % (iidx, bidx), (unittest.TestCase, base), {'ip': ip, 'browser': browser})
ut.setUp = setUp
ut.tearDown = tearDown
suites.append(unittest.TestLoader().loadTestsFromTestCase(ut))
unittest.TestSuite(suites)(results)
for obj, error in results.errors:
print 'In: ', obj
print error
if __name__ == "__main__":
main(SomeUnitTest)
Я знаю, знаю… в нем есть несколько заморочек, и, вполне возможно, что существуют более эффективные способы добиться того, чего добился я. Если этот код оскорбляет вас, еще раз посмотрите на то, что я говорил ранее: у меня было много дел, поэтому я не мог уделить много времени тому, чтобы отточить его до филигранности. Один момент, который, я думаю, можно сделать лучше – не просто склеивать динамические классы с помощью методов setUp и tearDown. Также, выход в конце выполнения теста также мог бы быть лучше. Ну ладно. Возможно, когда-нибудь, я вернусь к этому.
По существу, вы просто устанавливаете сервер, который вам необходимо протестировать и браузеры, в которых вы хотели бы, чтобы Selenium проводил тесты. Это в начале скрипта: IPS и BROWSERS. Затем создается новый класс unittest.TestCase для каждой комбинации IP/сервер + браузер. В итоге, каждый из тестовых случаев попадает в TestSuite, и последовательность тестов обработана. Если бы в ходе тестов были какие-либо ошибки, они были бы напечатаны. На самом деле мы не слишком беспокоились о возможности печати другой информации, но вы, конечно же, можете добавить печать любого другого важного параметра обратной связи.
В любом случае, я подумал, то кому-то может быть полезен мой небольшой эксперимент с вопросом моего коллеги. Буду рад вашим комментариям относительно вашего личного опыта и другими вариациями этого кода, которые вы считаете важными!