t.me/atinfo_chat Telegram группа по автоматизации тестирования

Повторное использование Selenium и UnitTest (Python)

unittest
webdriver
python
Теги: #<Tag:0x00007f9c574d80c8> #<Tag:0x00007f9c574dfd50> #<Tag:0x00007f9c574df490>

(Mykhailo Poliarush) #1

Вчера на работе, один из ребят из команды контроля качества подошел ко мне с вопросом, который оказался намного интереснее для меня, чем он изначально планировал (я так думаю). Он проводил тестирование элементов, используя 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, и последовательность тестов обработана. Если бы в ходе тестов были какие-либо ошибки, они были бы напечатаны. На самом деле мы не слишком беспокоились о возможности печати другой информации, но вы, конечно же, можете добавить печать любого другого важного параметра обратной связи.

В любом случае, я подумал, то кому-то может быть полезен мой небольшой эксперимент с вопросом моего коллеги. Буду рад вашим комментариям относительно вашего личного опыта и другими вариациями этого кода, которые вы считаете важными!


Формирование объектов на лету. Реализация на python
(Denis Repon) #2

выводит:


вообще у меня цель - используя один тестовый метод, подавать на него список с данными - и проход по кажд итерации из списка. как это сделать?