Передача информации между тест-кейсами unittest

Прошу помощи, только начинаю осваивать паттерны.

Тестирую гугло-поиск, используя PageObject паттерн + Python3 + unittest + WebDriver
Задача стоит примерно такая:

class GoogleSearch1:
используя вебдрайвер найти что-либо, проверить какие-либо данные в на странице результатов поиска (test_first, test_second, test_n), сохранить ссылку (driver.current_url) для последующего использования в других тест-кейсах

class GoogleSearch2:
не используя вебдрайвер (юзаю requests) открыть ссылку сохраненную предыдущим тест-кейсом, проверить какие-либо данные в полученном html (test_first, test_second, test_n)

Никак не пойму: можно ли это все красиво уместить в контексте PageObject? И как Вы передаете полученные данные тест-кейсами для их последующего использования?

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

3 лайка

А вообщем, поддерживаю @alex_okrushko лучше такого не делать, это дополнительная сложность, которой можно избежать. Ведь инстанс PageObject придется сохранять, т.е. сохранять его состояние и передавать между тестами.

Можно еще сделать обертку над unittest, чтобы через параметризацию теста передавать нужные данные на вход теста, ну и написать механизм зависимости между тестами.

Ну или если так нужны зависимости, то можно посмотреть в сторону proboscis фреймворка, ссылку можно найти тут awesome-test-automation/python-test-automation.md at master · atinfo/awesome-test-automation · GitHub там много реализовано зависимостей между тестами.

Также, например можно создать статический промежуточный прокси класс для хранения данных и потом от туда читать, но этот подход тоже имеет минусы.

В общем, задачу решить можно, только стоит задуматься, надо или это делать или нет.

  1. не знаю как в Pythone , в Java можно через
    Cookie cookie = new Cookie(name, value);
    webDriver.manage().addCookie(cookie);
  2. в xml записывать потом считывать .
1 лайк

Ну этот вариант подойдет, если тесты прогоняются в одной сессией. А если браузер закрывается, тогда подход не работает.

Емнип сookies не сразу удаляютья .

Я для этих целей записываю в файл результат теста, а потом в следующем его считываю, просто и сердито.

Действительно просто и сердито! :slight_smile:

Кстати в какой файл пишете .
xml , csv , properties ?

Обычный текстовый, так-как передается в основном 1-н параметр, а если нужно что-то более сложное, то думаю можно использовать JSON, XML, YML форматы, смотря кому что удобно и какие библиотеки доступны.

1 лайк

Для python можно заюзать модуль pickle. 11.1. pickle — Python object serialization — Python 2.7.18 documentation

1 лайк

С передачей информации или состояния в принципе разобрался. Нежелательно так делать, получается куча граблей. Тест-кейсы не должны зависеть друг от друга.

Прошу направить на верный путь со следующим вопросом: сколько же test_ может вмещать в себя один такой класс (GoogleTesting в данном случае)?

main.py
import unittest
from BaseTestCase import BaseTestCase


class GoogleTesting(BaseTestCase):
    def test_search_results_count(self):
        result = self.main_page.search('test test')  # поиск
        count = result.search_results_count() # кол-во результатов поиска

        self.assertGreaterEqual(12, count)  # or self.assertTrue(12 >= count)

    def test_is_domain_in_results(self):
        result = self.main_page.search('test test')  # снова поиск
        result_domains = result.search_results_domains()  # получаем домены из результатов поиска

        self.assertFalse('test.ru' in result_domains)


if __name__ == '__main__':
    unittest.main()
BaseTestCase.py
from selenium import webdriver
from pages.MainPage import MainPage
import unittest


class BaseTestCase(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(10)
        self.driver.get('http://google.com.ua')

        self.main_page = MainPage(self.driver)

    def tearDown(self):
        self.driver.quit()

Исходя из кода - класс GoogleTesting это один тест-кейс (или уже тест-сьют?). Может ли он вмещать в себе несколько test_?
Мне пока тяжело уместить в голове концепцию паттерна и основы мануального тестирования.

Получается такая картина:

  1. Инициализируем вебдрайвер, открываем гугл.
  2. Выполняем test_search_results_count
  3. Снова инициализация вебдрайвера
  4. Выполняем test_is_domain_in_results

Правильно ли это в контексте паттерна? Или стоит выполнить поиск единожды, а потом два раза проверить результаты?

Пардон, если вопросы кажутся тупыми =)

З.Ы. Может стоит делать setUp/tearDown отдельно для каждого класса?

если есть необходимость проверять тесты на каждом этапе их выполнения, использовать сериализацию не стандартных кросс-языковых решений - не есть хорошо. Пикл имеет плохо читаемый вид. Я бы посоветовал либо написать декоратор для сериализации нужных атрибутов кастомного класса в json, либо писать в csv или на худой конец в txt.

Человеко-читаемые и машинно читаемые данные для дебага промежуточный действий - самое оно.

В данном случае у вас GoogleTesting - сьют. Придумайте менее абстрактное название и все :smile: В рамках одного модуля можете писать сколько угодно сьютов (желательно конечно одной направленности, например по функционалу, странице и т.п.). Например:

test_bats.py:

    class TestGoogleSearch(BaseTestCase):
    
        pass
    
    class TestGoogleAuth(BaseTestCase):
    
        pass
    
    class TestGoogleDoodle(BaseTestCase):
    
         pass

Тест кейсы идеологически не должны быть связаны друг с другом, но если вы занимаетесь задачей, в которой контекст следующего теста вырождается из предыдущего тесткейса, а его вопроизведение чревато временными затратами (представьте, что вы тестируете поведение десктопного приложения на виртуальной машине) а его состояние не воспроизводимо и уникально, то лучший и идейно правильный способ - это запуск тестов в тест-кейсе по порядку. Далеко не так легко воссоздать контекст для изолированных тесткейсов, когда перед вами стоит необходимость протестировать шаги на валидацию какой-то одной сущности в среде куда более обширной, чем просто веб-сайт. Приведем пример: вы тестируете билд программы в определенной ОС и ваш сценарий подразумевает шаги инсталляции, базовой манипуляции с GUI и деинсталляцией. Каждый шаг можно протестировать отдельно, но если ваши тесты ставят собой задачу проверить всю вереницу манипуляций, то нет ничего проще, чем запустить тесты выполняться по очереди.

Для таких тестов достаточно алфавитно задать имена вроде test_a_program_setup_get_distrib_via_urllib и запускать их unittest.main() в случае, если вам достаточно одного класса, в котором описаны все тесты. Альтернативно можно создать сьюты, в которые вы в ручную добавите

suite = unittest.TestSuite()
suite.addTest(ContainerCreationFactoryTest(testname = ‘test_a_start_setup_via_http’))
unittest.TextTestRunner().run(suite)

где ContainerCreationFactoryTest - класс теста, который вы создали унаследовавшись от unittest.TestCase.

Ничто не мешает вам создать разные Сьюты и добавить в них разные тесты из общего вашего ТестКейс класса, если есть необходимость в разных комбинациях ваших тестов.

Разрешите поправить Вас, дело не в менее абстрактном названии, а скорее том, что Сьют - это совокупность тест-кейсов. Сам по себе класс унаследованный от unittest.TestCase можеть быть ‘сьютом’ только в вопросе “как мне проще это понимать”, и то понимание это не совсем верное в ключе терминологии.

GoogleTesting автора это тест-кейс. а для сьюта есть соответствующий сьюту код инициализации и проч. :wink:
я бы назвал использование unittest.main() в качестве парсинга определений классов и запуска юнит-тестов начальным вариантом, когда у разработчика есть один всего лишь тест-кейс.