Порядок исполнения python объединяет их декларацией - PullRequest
0 голосов
/ 04 марта 2020

Я использую python юнит-тесты и селен, и в моем коде у меня есть один тестовый класс со многими тестовыми сценариями:

class BasicRegression(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.driver = webdriver.Chrome(executable_path=Data.driver)
        cls.driver.implicitly_wait(1)
        cls.driver.maximize_window()

    def testcase1_some_stuff(self):
        do_something()

    def testcase2_some_stuff(self):
        do_something()

    def testcase3_some_stuff(self):
        do_something()

    ...

    @classmethod
    def tearDownClass(cls):
        cls.driver.close()
        cls.driver.quit()

if __name__ == '__main__':
    unittest.main()

Тесты выполняются в алфавитном порядке, т.е. testcase1, testcase2 и testcase3, до testcase9. Стандарт. Проблема возникает с testcase10 и т. Д., Который выполняется первым.

У меня вопрос, как я могу установить порядок их выполнения?

1 Ответ

0 голосов
/ 04 марта 2020

Для начала юнит-тесты должны быть независимыми. Так должно быть . Тесты, выполненные с помощью python-unittest, должны быть спроектированы таким образом, чтобы они могли выполняться независимо. Чистые модульные тесты предлагают то преимущество, что когда они терпят неудачу, они часто показывают, что именно пошло не так. Тем не менее, мы склонны писать функциональные тесты, интеграционные тесты и системные тесты с каркасом unittest, и эти тесты невозможно будет выполнить без их заказа, поскольку Selenium автоматизирует контекст просмотра . Чтобы добиться упорядочения, по крайней мере, вам нужно использовать лучшее соглашение об именах для имен тестов, например: test_1, test_2, test_3, et c, и это работает, потому что тесты отсортированы по отношению к встроенный порядок для строк.

Однако, согласно вашему наблюдению, проблема возникает с test_10 и т. д., где порядок сортировки нарушается. Например, среди 3 тестов с именами test_1, test_2 и test_10 кажется, что unittest выполняет test_10 до test_2:

  • Код:

    import unittest
    
    class Test(unittest.TestCase):
    
        @classmethod
        def setUp(self):
            print("I'm in setUp")
    
        def test_1(self):
            print("I'm in test 1")
    
        def test_2(self):
            print("I'm in test 2")
    
        def test_10(self):
            print("I'm in test 10")
    
        @classmethod
        def tearDown(self):
            print("I'm in tearDown")
    
    if __name__ == "__main__":
        unittest.main()
    
  • Вывод на консоль:

    Finding files... done.
    Importing test modules ... done.
    
    I'm in setUp
    I'm in test 1
    I'm in tearDown
    I'm in setUp
    I'm in test 10
    I'm in tearDown
    I'm in setUp
    I'm in test 2
    I'm in tearDown
    ----------------------------------------------------------------------
    Ran 3 tests in 0.001s
    
    OK
    

Решение

В различных обсуждениях предлагались разные решения, и некоторые из них:

  • @ max в обсуждении Порядок тестов Unittest предложил установить sortTestMethodsUsing в None следующим образом:

    import unittest
    unittest.TestLoader.sortTestMethodsUsing = None
    
  • @ atomocopter в обсуждении изменение порядка юнит-тестов в Python предложил установить sortTestMethodsUsing на некоторое значение следующим образом:

    import unittest
    unittest.TestLoader.sortTestMethodsUsing = lambda _, x, y: cmp(y, x)
    
  • @ ElmarZander в обсуждении Порядок тестов Unittest предложил использовать nose и писать свои тестовые сценарии как функции (а не как методы некоторого производного класса TestCase) nose hasn не работайте с порядком, но используйте порядок функций, определенный в файле.

  • @ Keiji в обсуждении Управление порядком unittest.TestCases упоминает:

sortTestMethodsUsing ожидает функцию, подобную Python 2's cmp, которая не имеет эквивалента в Python 3 (Я проверял, есть ли у Python 3 оператор <=> космического корабля, но, видимо, нет; они ожидают, что вы будете полагаться на отдельные сравнения для < и ==, что кажется шагом назад ...). Функция принимает два аргумента для сравнения и должна возвращать отрицательное число, если первый меньше. В частности, в этом конкретном случае функция может предполагать, что аргументы никогда не равны, поскольку unittest не будет помещать дубликаты в список имен тестов.

С учетом этого, вот я нашел самый простой способ сделать это, предполагая, что вы используете только один класс TestCase:

def make_orderer():
    order = {}

    def ordered(f):
        order[f.__name__] = len(order)
        return f

    def compare(a, b):
        return [1, -1][order[a] < order[b]]

    return ordered, compare

ordered, compare = make_orderer()
unittest.defaultTestLoader.sortTestMethodsUsing = compare

Затем аннотируйте каждый метод тестирования с помощью @ordered:

class TestMyClass(unittest.TestCase):
    @ordered
    def test_run_me_first(self):
        pass

    @ordered
    def test_do_this_second(self):
        pass

    @ordered
    def test_the_final_bits(self):
        pass

if __name__ == '__main__':
    unittest.main()

Это зависит от Python вызова аннотаций в порядке появления аннотированных функций в файле. Насколько я знаю, это задумано, и я бы удивился, если бы это изменилось, но я на самом деле не знаю, гарантировано ли это поведение. Я думаю, что это решение будет работать даже в Python 2, для тех, кто, к сожалению, застрял с ним, хотя у меня не было возможности проверить это.

Если у вас есть несколько классов TestCase, вы Вам нужно будет запустить ordered, compare = make_orderer() один раз для каждого класса до определения class, хотя то, как это можно использовать с sortTestMethodsUsing, будет более сложным, и я пока еще не смог проверить это.

Для справки, код, который я тестирую, не полагается на исправление порядка тестирования, и я полностью понимаю, что вы не должны полагаться на заказ теста, и именно поэтому люди используют его, чтобы не отвечать этот вопрос. Порядок моих тестов можно было бы рандомизировать, и это сработало бы так же хорошо. Однако есть одна очень веская причина, по которой я бы хотел, чтобы порядок был зафиксирован в том порядке, в котором они определены в файле: это намного упрощает просмотр с первого взгляда , который тесты не удался.

...