
Selenium
Selenium — это очень удобный (имхо) инструмент для тестирования веб-приложений.
Тесты создаются с помощью дополнения для Firefox, которое может генерировать код теста на различных языках, в том числе и на Python. Затем эти тесты выполняются специальным сервером, Selenium RC.
Сам по себе Selenium не привязан ни к языкам ни к фреймворкам, поэтому чтобы интегрировать его в систему тестирования Django-приложений, нужно приложить очень небольшие усилия.
Для решения задачи интеграции я буду использовать библиотеку Django: Sane Testing. Это библиотека, расширяющая возможности стандартной системы тестирования Django, в том числе и поддержкой тестов Selenium.
Ставим Django: Sane Testing
Установка этой библиотеки была бы стандартной, если бы она не тянула за собой Django. Что не есть правильно, если вы пользуетесь транком, как и я.
Скачиваем актуальный релиз, распаковываем (можно в /tmp), открываем setup.py, находим
install_requires = ['Django>=1.0_final','nose>=0.10'], <br/>
либо удаляем, либо комментим часть про Django. После этого ставим:
sudo python setup.py install
Ставим Selenium
Нужно поставить сервер и плагин для Firefox. И то, и другое находится на странице загрузки.
Для установки плагина достаточно открыть ссылку Selenium IDE, разрешить установку плагина, установить его и перезапустить Firefox. Кроме того, уважаемый bazzzman написал расширение для этого плагина (!), для удобства работы.
Для установки сервера нужно скачать архив по ссылке Selenium RC, распаковать его куда-нибудь. В получившемся после распаковки каталоге будет несколько подкаталогов. Среди них будет selenium-server-x.y.z, это каталог с сервером. Сам сервер — это файл selenium-server.jar. Вот его куда-нибудь копируем, в удобное место, например в /usr/local/lib, после чего весь распакованный каталог можно потереть, он больше не нужен.
Для удобного запуска создаём скрипт,
sudo nano /usr/local/bin/selenium-server
с таким содержимым:
#!/bin/bash
/usr/bin/env java -jar /usr/local/lib/selenium-server.jar
Задаём ему права на выполнение:
sudo chmod 755 /usr/local/bin/selenium-server
Проверим: после выполнения команды /usr/local/bin/selenium-server должно появляться что-то эдакое:
23:58:17.788 INFO - Java: Sun Microsystems Inc. 14.2-b01
23:58:17.798 INFO - OS: Linux 2.6.31-14-generic i386
23:58:17.863 INFO - v1.0.1 [2696], with Core v@VERSION@ [@REVISION@]
23:58:18.111 INFO - Version Jetty/5.1.x
23:58:18.113 INFO - Started HttpContext[/selenium-server/driver,/selenium-server/driver]
23:58:18.114 INFO - Started HttpContext[/selenium-server,/selenium-server]
23:58:18.114 INFO - Started HttpContext[/,/]
23:58:18.166 INFO - Started SocketListener on 0.0.0.0:4444
23:58:18.166 INFO - Started org.mortbay.jetty.Server@fc9944
если так и есть, значит сервер работает ОК.
Тестовый проект
Создаём тестовый проект:
django-admin.py startproject justtotest
В проекте будет одно приложение, назовём его habrahabr:
./manage.py startapp habrahabr
Наш тестовый хабр будет состоять из одной модели:
class Greeting(models.Model):
text = models.CharField(max_length=200)
одной формы для ввода приветствия:
class GreetingForm(forms.ModelForm):
text = forms.CharField(widget=forms.TextInput(attrs={'size':'40'}),
error_messages={'required': 'А текст приветствия ввести ? '})
class Meta:
model = Greeting
и одной вьюшки:
def Greetings(request):
template_name = 'habrahabr/index.html'
title='Selenium'
if request.method == 'GET':
form = GreetingForm()
else:
form = GreetingForm(request.POST)
if form.is_valid():
text = form.cleaned_data['text']
new_greeting=Greeting(text=text)
new_greeting.save()
return HttpResponseRedirect('/')
greetings = Greeting.objects.all().order_by('-id')
context = {
'title': title,
'greetings': greetings,
'form': form,
}
return render_to_response(template_name, context,
context_instance=RequestContext(request))
на которой выводится список добавленных ранее приветствий и форма для добавления нового приветствия.
Создание теста Selenium
Запустим проект и в браузере создадим тест с помощью плагина, смотрите на видео (советую смотреть в HQ):
Как видите, у нас получился код на питоне. Из этого сгенерированного кода возьмём файл класса и немножко доработаем его, чтобы в нашем tests.py получилось вот такое:
# coding: utf-8
from djangosanetesting.selenium.driver import selenium
import unittest, time, re
class Untitled(unittest.TestCase):
test_type = «selenium»
start_live_server = True
def setUp(self):
self.start_live_server=True
self.verificationErrors = []
self.selenium = selenium(«localhost», 4444, "*chrome", «127.0.0.1:8000/»)
self.selenium.start()
def test_required_text_exists(self):
sel = self.selenium
sel.open("/")
sel.type(«id_text», «Testing with Selenium»)
sel.click(u"//input[@value='Добавить']")
sel.wait_for_page_to_load(«30000»)
try: self.failUnless(sel.is_text_present(«Testing with Selenium»))
except AssertionError, e: self.verificationErrors.append(str(e))
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
В класс мы добавили два атрибута.
test_type
— указывает на тип теста и start_live_server
— он говорит о том, что нужно будет запускать тестовый сервер.Кроме того, импорты другие, после установки sane у нас уже всё есть в установленном пакете.
Скрипты для запуска тестов
Есть два варианта настроек для запуска тестов. Первый вариант — добавить в settings.py переменную
TEST_RUNNER
, но в этом случае не получится выбирать индивидуальные типы тестов, например, только юнит-тесты, или только селениум-тесты, а ведь не всегда нужно запускать все.Поэтому я выбрал второй вариант — написал скрипты для запуска тестов. Первый скрипт, nose-selenium:
#!/bin/bash
DJANGO_SETTINGS_MODULE=«settings» PYTHONPATH=".:.." nosetests --with-django --with-djangoliveserver --with-sanetestselection --select-seleniumtests;
этот скрипт запустит селениум-тесты с тестовым сервером.
Второй скрипт, nose-unittests:
#!/bin/bash
DJANGO_SETTINGS_MODULE=«settings» PYTHONPATH=".:.." nosetests --with-django --with-sanetestselection --select-unittests;
этот скрипт запустит юнит-тесты, без тестового сервера.
Можно сделать необходимые скрипты на все случаи жизни, все типы тестов перечислены в документации. Не забудьте установить права на выполнение скриптов,
chmod 755
. Запуск тестов
Теперь всё готово для запуска тестов. Необходимо стартануть сервер Selenium, /usr/local/bin/selenium-server, после чего можно запускать тесты с помощью скриптов.
Я не стал делать скринкаст, но будьте уверены, что всё работает ОК — запускается браузер, контачит с сервером, заполняет форму, проверяет наличие текста, результаты выводятся как обычно.
Код к статье выложил на яндексе, если файл оттуда исчезнет, пишите в личку.
Резюме
На мой взгляд, селениум является хорошим дополнением к системе тестов, т.к. позволяет тестить javascript-насыщенные интерфейсы, что стандартной системе тестов не под силу. Кроме того, сама по себе Django: Sane Testing предлагает дополнительные фичи, о которых я вам советую прочесть в документации.
Надеюсь, моя статья будет полезной для широкого круга Django-разработчиков, как начинающих, так и опытных. От опытных разработчиков жду комментов по теме :-)
P.S.
Windmill не пробовал. Если она проще\лучше\надёжнее, чем Selenium, пожалуйста опишите в комментах или в виде статьи. Линк на статью помещу в начало этой.