📜 ⬆️ ⬇️

Functional tests: Django + Selenium WebDriver and 3 options of your choice

image

“In the life of every Django developer, there comes a moment when he vigorously vomits with his past, devoid of functional testing!”

About this and talk.

This article is the result of finding the best testing tool for ready-made pages of a small project. For the criterion for assessing the optimality of a tool, we conditionally take the minimum test execution time while striving for equal conditions of each of the sets of applications.

The article discusses 3 options for functional testing of Django applications in Python 3.4 under Django 1.7 using Selenium WebDriver (there are articles on Habré with a detailed description of the features of Selenium here and here ). And then the full information on the Selenium WebDriver API. More documentation in Russian and examples of use .

The tests used technologies and applications: VirtualBox 4.3.6, Debian 7.7, Virtualenv 12.0.7, Python 3.4, Django 1.7, Selenium Webdriver 2.47.3, Iceweasel, Xvfb, PyVirtualDisplay 0.1.5, PhantomJS 1.9.8, Nginx 1.2.1 , uWSGI.
')
Consider the following bundles for Debian 7.7 + Virtualenv 12.0.7 + Django 1.7 +:


Functional testing tools allow you to assess the performance of the target site and the behavior of pages in the browser, as well as help if the basic Django test client is not convenient for testing dynamically loaded data (using JavaScript, Ajax). When different technologies are combined in a single product and a natural question arises how they will behave together in this or that case.

With these tools, we can simulate real user behavior.

Let's get started!

In the virtual environment set Selenium:

pip install selenium 

In our case, we will test the user authentication process, so we will create the tests.py file in the authentication application (Item B).

Option 1. Visual simulation of user behavior


A. We assume that the graphical user interface is installed, here - X.org.

We put Debian Iceweasel (formerly Debian Firefox - modification of Mozilla Firefox browser in Debian GNU / Linux):

 sudo apt-get install iceweasel 

! Note:
When we try to run the test from the terminal, without launching the graphical environment, we will get an exception: raise WebDriverException ("The browser appears to have exegee.common.exceptions.WebDriverException: If you Specified a log_file in the FirefoxBinary constructor, check it for details.)

B. Create a file tests.py.

Option 1
 #    Django    Selenium from django.test import LiveServerTestCase #     ( FireFox) from selenium import webdriver import time class SeleniumTests(LiveServerTestCase): def test_auth(self): #  webdriver Firefox br = webdriver.Firefox() #    ,    'localhost:8081'   URL br.get('%s%s' % (self.live_server_url, '/')) #     br.find_element_by_xpath('//a[@href="/register/"]').click() #  3  time.sleep(3) #   #   username    'new' br.find_element_by_id('username').send_keys('new') #   email    'new@new.ru' br.find_element_by_id('email').send_keys('new@new.ru') #    2-  br.find_element_by_id('password1').send_keys('12345678') br.find_element_by_id('password2').send_keys('12345678') #     br.find_element_by_id('btn_register').click() #      pis = Myuser.objects.get(username='new') #    -  pis.is_active = True #    pis.save() #     br.find_element_by_xpath('//a[@href="/"]').click() #  3  time.sleep(3) #     br.find_element_by_id('username').send_keys('new') br.find_element_by_id('password').send_keys('12345678') br.find_element_by_name('').click() #         assert br.find_element_by_xpath('//a[@data-content=" "]').text == 'new' #  ,   br.quit() 


! Note:
It is necessary to pause time.sleep (3) in the program text to avoid the error: “selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: {" method ":" id "," selector ":" username "}" , “Can not find element”, caused by the fact that it did not have time to load the whole context of the page. If an error occurs, you can increase the wait time.

B. Run our test from authentication / tests.py:
 python manage.py test authentication/ 

More startup options.
All project tests:
 python manage.py test 

Specific class SeleniumTests from tests.py:
 python manage.py test authentication.tests.SeleniumTests 

The test_auth method of the SeleniumTests class:
 python manage.py test authentication.tests.SeleniumTests.test_auth 


TIME OF TEST WORK (Debian 7.7, VirtualBox, 12 Mb VideoRAM, 512 Mb RAM, 1 core): (29.89 + 25.65 + 26.73) / 3 = 27.42 sec

Option 2. Running tests through the terminal without launching the GUI on xvfb + pyvirtualdisplay


A. To run from the console, you need to install the Virtualenv X server in a virtual environment: Xvfb and virtual display: Pyvirtualdisplay.

 sudo apt-get install xvfb pip install pyvirtualdisplay 

! Note:
We set PyVirtualDisplay on behalf of a local user, otherwise when testing from under a user in the import line: from pyvirtualdisplay import Display, there will be an error.
PyVirtualDisplay 0.1.5 officially supports python versions: 2.6, 2.7, 3.2, 3.3, tested at 3.4 - it works

B. Create a file tests.py. To the previously described in Option 1 we add lines for working with a virtual display.

Option 2
 #    from pyvirtualdisplay import Display #    Django    Selenium from django.test import LiveServerTestCase #     ( FireFox) from selenium import webdriver import time class SeleniumTests(LiveServerTestCase): def test_auth(self): #      display = Display(visible=0, size=(800, 600)) display.start() #  webdriver Firefox br = webdriver.Firefox() #    ,    'localhost:8081'   URL br.get('%s%s' % (self.live_server_url, '/')) #     br.find_element_by_xpath('//a[@href="/register/"]').click() #  3  time.sleep(3) #   #   username    'new' br.find_element_by_id('username').send_keys('new') #   email    'new@new.ru' br.find_element_by_id('email').send_keys('new@new.ru') #    2-  br.find_element_by_id('password1').send_keys('12345678') br.find_element_by_id('password2').send_keys('12345678') #     br.find_element_by_id('btn_register').click() #      pis = Myuser.objects.get(username='new') #    -  pis.is_active = True #    pis.save() #     br.find_element_by_xpath('//a[@href="/"]').click() #  3  time.sleep(3) #     br.find_element_by_id('username').send_keys('new') br.find_element_by_id('password').send_keys('12345678') br.find_element_by_name('').click() #         assert br.find_element_by_xpath('//a[@data-content=" "]').text == 'new' #    display.stop() #  ,   br.quit() 


TEST WORKING TIME (Putty SSH, Screen, Virtualenv, Debian 7.7, VirtualBox, 12 Mb VideoRAM, 512 Mb RAM, 1 core): (28.5 + 25.82 + 24.98) / 3 = 26.43 sec

Option 3. Running tests through the terminal without launching the GUI on PhantomJS


A. To run from the console, you need to install PhantomJS:

 cd /usr/local/share sudo wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.8-linux-x86_64.tar.bz2 sudo tar xjf phantomjs-1.9.8-linux-x86_64.tar.bz2 sudo ln -s /usr/local/share/phantomjs-1.9.8-linux-x86_64/bin/phantomjs /usr/local/share/phantomjs sudo ln -s /usr/local/share/phantomjs-1.9.8-linux-x86_64/bin/phantomjs /usr/local/bin/phantomjs sudo ln -s /usr/local/share/phantomjs-1.9.8-linux-x86_64/bin/phantomjs /usr/bin/phantomjs 

And run:

 phantomjs -v 

! Note:
If the received packet is not suitable for this system, we get an error: “I can not run a binary file” (Often due to an attempt to install a 64-bit application (x64) on a 32-bit system (x86)).

B. Create a file tests.py. To the previously described in Option 1 we add lines for working with PhantomJS.

Option 3
 #  PhantomJS from selenium.webdriver import PhantomJS #    Django    Selenium from django.test import LiveServerTestCase import time #   #     ( FireFox) #from selenium import webdriver class SeleniumTests(LiveServerTestCase): def test_auth(self): #   #  webdriver Firefox #br = webdriver.Firefox() #   PhantomJS br = PhantomJS() #    br.set_window_size(800, 600) #    ,    'localhost:8081'   URL br.get('%s%s' % (self.live_server_url, '/')) #     br.find_element_by_xpath('//a[@href="/register/"]').click() #  3  time.sleep(3) #   #   username    'new' br.find_element_by_id('username').send_keys('new') #   email    'new@new.ru' br.find_element_by_id('email').send_keys('new@new.ru') #    2-  br.find_element_by_id('password1').send_keys('12345678') br.find_element_by_id('password2').send_keys('12345678') #     br.find_element_by_id('btn_register').click() #      pis = Myuser.objects.get(username='new') #    -  pis.is_active = True #    pis.save() #     br.find_element_by_xpath('//a[@href="/"]').click() #  3  time.sleep(3) # : #     br.save_screenshot('screenshot_firstpage.png') #     br.find_element_by_id('username').send_keys('new') br.find_element_by_id('password').send_keys('12345678') br.find_element_by_name('').click() #         assert br.find_element_by_xpath('//a[@data-content=" "]').text == 'new' #  ,   br.quit() 


When creating a screenshot, PhantomJS has a problem with the background, while saving it is transparent (black background). To correct this misunderstanding before br.save_screenshot ('screenshot_firstpage.png') you can use
such code:
br.execute_script ("" "(function () {
var style = document.createElement ('style'), text = document.createTextNode ('body {background: #fff}');
style.setAttribute ('type', 'text / css');
style.appendChild (text);
document.head.insertBefore (style, document.head.firstChild);
}) (); "" ")


TIME TEST WORK without creating a screenshot of the page (Putty SSH, Screen, Virtualenv, Debian 7.7, VirtualBox, 12 Mb VideoRAM, 512 Mb RAM, 1 core): (14.64 + 14.89 + 13.05) / 3 = 14.19 sec .

Added by:
TIME TEST WORK with a screenshot of the page (Putty SSH, Screen, Virtualenv, Debian 7.7, VirtualBox, 12 Mb VideoRAM, 512 Mb RAM, 1 core): (17.63 + 17.74 + 17.94) / 3 = 17.77 sec .

image



Summary:


Using Option 3 without page screenshot - [ 14.19 sec. ] provides almost 2 times less time for smoke breaks than Option 2 - [26.43 sec.] and Option 1 - [27.42 sec.] and is suitable for use on a combat server without a graphical shell. But Option 1 is visually informative and convenient for preliminary tests during development, before rolling out the code to a combat server.

PS Here it is necessary to further note that in the test code a total of 6 seconds were used. waiting

Added by:
Dear colleagues, what kind of bundles do you use in functional testing? What are their advantages and disadvantages?

Thanks for attention!

Source: https://habr.com/ru/post/268385/


All Articles