SlideShare une entreprise Scribd logo
1  sur  46
Télécharger pour lire hors ligne
Automating Django
FunctionalTests Using
Selenium on Cloud
Jonghyun Park, Lablup Inc.
2016/08/14 (Sun) @PyCon APAC 2016
Contents and target audience
•How to functional tests on Django
using Selenium.
• Running functional tests automatically on AWS EC2.
• And some tips on writing functional tests (if time permits).
• Target audience
• Python beginners - intermediates.
• Who have written some tests in Python/Django
• … but not much.
About speaker
• Physics (~4 yr)
• Single-molecule Biophysics (~8 yr)
• Optical microscope
• DNA, protein
• IT newbie (~1.2 yr)
• HTML, CSS, Javascript, Polymer (Google)
• Python-Django
About speaker
CodeOnWeb (codeonweb.com)
CodeTest
General remarks about code testing
Tests on CodeOnWeb
Test code
• Code that tests code.
def login(username, password, ...):
...
if success: return True
else: return False
def test_login():
result = login('test', '1' , ...)
assertTrue(result)
Test
login.py
test_login.py
Why tests code?
• How do we know our code is okay even if we are
messing around all the parts of the code?
• Ensure minimal code integrity when refactoring.
• Man cannot test all features by hand.
• Pre-define requirements for a feature.
Test-Driven Development (TDD)
https://goo.gl/IPwERJ
Some people actually do!
Writing tests is good for newbie
• Can understand the logic of each function/module
• … w/o destroying real service whatever you do.
• Defeat bugs & improves codes, if you are lucky.
https://goo.gl/sU2D2M
There are stupid codes, but not stupid test codes!
like me
Kinds of tests for CodeOnWeb
• Unit tests
• Test of independent unit of behavior.
• e.g., function, class method.
• Test layer: model / form / view.
• Functional tests
• Test of independent piece of functionality.
• May test many functions or methods.
• Test of actual user interaction on the web browser.
lenium
Using Selenium
Functional testing using selenium with Django
Selenium
• Browser emulator.
• Automate user interaction
on the browser.
• Can be utilized for testing
… and other things.
python manage.py test
functional_tests.test_login_registration
.LoginTest
Browser (Firefox, Chrome, …)
Selenium
Webdriver
Test scheme using Selenium
Install Selenium
pip install selenium
Get browser through webdriver
browser = webdriver.Firefox()
Visit web page
browser.get(url)
Do whatever you want Test response is expected
browser.find_element_by_id(
'lst-ib').send_keys('haha')
self.assertEqual(...)
self.assertTrue(...)
Example: automating googling
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
# Get browser through webdriver
browser = webdriver.Firefox()
# Visit Google!
browser.get('https://google.com/')
# Enter keyword and enter
inp = browser.find_element_by_id('lst-ib')
inp.send_keys('PyCon 2016')
inp.send_keys(Keys.RETURN)
# Just wait a little
time.sleep(3)
# Close browser window
browser.quit()
python functional_tests/test_pycon_google1.py
This is not a test case!
Convert to Django’s test case
import time
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class GoogleTest(StaticLiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.set_window_size(1024, 768)
def tearDown(self):
time.sleep(3)
self.browser.quit()
def test_google_search(self):
self.browser.get('https://google.com/')
inp = self.browser.find_element_by_id('lst-ib')
inp.send_keys('PyCon 2016')
inp.send_keys(Keys.RETURN)
live django server
+ collect static files
python functional_tests/test_pycon_google2.py(X)
python manage.py test functional_tests.test_pycon_google2(O)
Finding elements
browser.find_element_by_id('loginForm')
.find_element_by_css_selector('input[name="username"]')
.find_element_by_name('username')
.find_element_by_class_name('login')
.find_element_by_tag_name('input')
.find_element_by_tag_link_text('Go to Google')
.find_element_by_tag_partial_link_text('Go to')
.find_element_by_xpath('//form[@id=" loginForm "]')
<html>
<body>
<form id="loginForm" class="login">
<input name="username" type="text" />
<input name="password" type="password" />
<input name="continue" type="submit" value="Login" />
</form>
<a href=”https://google.com/">Go to Google</a>
</body>
<html>
browser.find_elements_by_id('loginForm')
...
Interacting with elements
item = browser.find_element_by_id('entry-item')
item.click()
ui_type = item.get_attribute('ui-type')
browser.execute_script(
'arguments[0].setAttribute("disabled", "true")',
item,
)
browser.execute_script(
'arguments[0].querySelector("paper-menu").selected = arguments[1]',
item, '2'
)
Not that difficult if you know Javascript.
Let’s write a login test
def test_user_login(self):
# Store login count of the user
user = get_user_model().objects.get(username='einstein')
logincount = user.profile.logincount
# visit root url ('/')
self.browser.get(self.live_server_url)
# Try to login with email and password
self.browser.find_element_by_name('email').send_keys('einstein@lablup.com')
self.browser.find_element_by_name('password').send_keys('1')
self.browser.find_element_by_css_selector('fieldset paper-button').click()
# Confirm login count is increased by 1
user = get_user_model().objects.get(username='einstein')
self.assertEqual(user.profile.logincount, logincount + 1)
# Check visit correct url
target_url = self.live_server_url + '/accounts/profile/usertype/'
self.assertEqual(self.browser.current_url, target_url)
python manage.py test functional_tests.test_pycon_login
Waits in Selenium
Waiting is very important
Selenium, the beauty of waiting
• Wait what?
• Page loading
• Elements loading
• Elements visibility
• Ajax response
• DB operation
• …
https://goo.gl/5ykwc4
Broken login example
def test_user_login(self):
# Store login count of the user
user = get_user_model().objects.get(username='einstein')
logincount = user.profile.logincount
# visit root url ('/')
self.browser.get(self.live_server_url)
# Try to login with email and password
self.browser.find_element_by_name('email').send_keys('einstein@lablup.com')
self.browser.find_element_by_name('password').send_keys('1')
self.browser.find_element_by_css_selector('fieldset paper-button').click()
# Confirm login count is increased by 1
user = get_user_model().objects.get(username='einstein')
self.assertEqual(user.profile.logincount, logincount + 1)
# Check visit correct url
target_url = self.live_server_url + '/accounts/profile/usertype/'
self.assertEqual(self.browser.current_url, target_url)
python manage.py test functional_tests.test_pycon_login
Selenium do not wait
automatically
login.html
submit()
views.py
…
user.profile.logincount += 1
user.profile.save()
...
render logged_in.html
logged_in.html
test_pycon_login.py
user.profile.logincount Which one is faster?
Selenium do not wait
automatically
browser.get("http://www.google.com")
Dependent on several factors, including the
OS/Browser combination, WebDriver may
or may not wait for the page to load.
Waiting methods in Selenium
• Implicit wait
• Explicit wait
• Stupid wait
• It is highly un-recommended to wait for specific
amounts of time.
• If target is loaded in 5 s, we waste the remaining time.
• If target is not loaded in 5 s, the test fails (slow system).
import time
time.sleep(5)
Provided by Selenium
Implicit wait
• Official DOC:
• Easy to use, global effect.
• Applies only for element waiting.
An implicit wait is to tell WebDriver to poll the DOM for a certain amount
of time when trying to find an element or elements if they are not
immediately available.The default setting is . Once set, the implicit wait is
set for the life of theWebDriver object instance.
browser = webdriver.Firefox()
browser.implicitly_wait(10) # in seconds
browser.get("http://somedomain/url_that_delays_loading")
myDynamicElement = browser.find_element_by_id("myDynamicElement")
Implicit wait
• Waiting behavior is determined on the “remote”
side of the webdriver.
• Different waiting behavior
on different OS, browser,
versions, etc.
• Return element immediately
• Wait until timeout
• …
def implicitly_wait(self, time_to_wait):
self.execute(Command.IMPLICIT_WAIT, {'ms': float(time_to_wait) * 1000})
WebDriver RemoteConnection.execute()
Browser (Firefox, Chrome, …)
Selenium
Webdriver
Explicit wait
• Official DOC:
• A little messy, local effect.
An explicit wait is code you define to wait for a certain condition to occur
before proceeding further in the code. …WebDriverWait in combination with
ExpectedCondition is one way this can be accomplished.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
import selenium.webdriver.support.expected_conditions as EC
ff = webdriver.Firefox()
ff.get("http://somedomain/url_that_delays_loading")
try:
element = WebDriverWait(ff, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
finally:
ff.quit()
Explicit wait
• Highly flexible (variety of expected conditions)
EC.title_is(...)
.title_contains(...)
.presence_of_element_located(...)
.visibility_of_element_located(...)
.visibility_of(...)
.presence_of_all_elements_located(...)
.text_to_be_present_in_element(...)
.text_to_be_present_in_element_value(...)
.frame_to_be_available_and_switch_to_it(...)
.invisibility_of_element_located(...)
.element_to_be_clickable(...)
.staleness_of(...)
.element_to_be_selected(...)
.element_located_to_be_selected(...)
.element_selection_state_to_be(...)
.element_located_selection_state_to_be(...)
.alert_is_present(...)
Explicit wait
• Highly flexible (not limited for waiting element)
• Waiting is controlled on the “local” side.
• Defined behavior. def until(self, method, message=''):
end_time = time.time() + self._timeout
while(True):
try:
value = method(self._driver)
if value:
return value
except self._ignored_exceptions:
pass
time.sleep(self._poll)
if(time.time() > end_time):
break
raise TimeoutException(message)
condition = lambda _: self.browser.execute_script('return document.readyState') == 'complete'
WebDriverWait(self.browser, 30).until(condition)
Browser (Firefox, Chrome, …)
Selenium
Webdriver
Use explicit wait
• Use explicit wait!
• In good conditions (OS, browser, version), implicit
wait can simplify test codes.
• Be aware that the condition may change in the future.
• I think implicit wait is not very stable way to go.
• Never use stupid wait.
• Except in a very limited cases (like presentation?).
RunningTests on Cloud
(AWS EC2)
Functional tests: automatically once a day
Run selenium on AWS
• No screen
• Virtual display
• Slow machine (low cost)
• Give timeout generously
• That’s all!
Run selenium on AWS
# Install headless java
sudo apt-get install openjdk-6-jre-headless
# Fonts
sudo apt-get install xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic
# Headless X11 magic is here
sudo apt-get install xvfb
# We still demand X11 core
sudo apt-get install xserver-xorg-core
# Firefox installation
sudo apt-get install firefox
# Download Selenium server
wget http://selenium.googlecode.com/files/selenium-server-standalone-2.31.0.jar
# Run Selenium server
Xvfb :0 -screen 0 1440x900x16 2>&1 >/dev/null &
export DISPLAY=:0
nohup xvfb-run java -jar selenium-server-standalone-2.53.0.jar > selenium.log &
http://goo.gl/GRbztO
+ crontab
Test automation for CodeOnWeb
Unit tests
Functional tests
Local1
Test server (on EC2)
git commit; git push
Actual codes
Github
Github-Auto-Deploy
(listen hook run scripts)
hook
git pull
post-merge hook
Run DB migration
Run unit tests
listen
err no err
Error posting script
Run functional tests
errno err
Unit tests
Functional tests
Local2
git commit; git push
Actual codes
once a day
comment on issue
…
Slack integration is also possible
SomeTips
Most of them is on the web.
Faster password hasher
• Use fastest password hasher (MD5) in testing.
• Django’s default: PBKDF2 algorithm with SHA256 hash.
• It’s more secure, but quite slow.
• In our case, this reduces the test running time by
• half (for unit tests).
• ~10% (for functional tests).
• Never use this in production server.
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.MD5PasswordHasher',
]
settings.py
Shorter login
from django.conf import settings
from django.contrib.auth import get_user_model, BACKEND_SESSION_KEY,
SESSION_KEY, HASH_SESSION_KEY
from django.contrib.sessions.backends.db import SessionStore
def login_browser(self, username='einstein'):
# Set fake session
user = get_user_model().objects.get(username=username)
session = SessionStore()
session[SESSION_KEY] = user.pk
session[BACKEND_SESSION_KEY] = 'django.contrib.auth.backends.ModelBackend'
session[HASH_SESSION_KEY] = user.get_session_auth_hash()
session.save()
# To set cookies, the browser should visit a page (due to same origin policy).
# It is faster to visit dummy page than login page itself.
self.browser.get(self.live_server_url + '/selenium_dummy')
self.browser.add_cookie({
'name': settings.SESSION_COOKIE_NAME,
'value': session.session_key,
'secure': False,
'path': '/'
})
Tests for logged-in user is requred.
Fluently wait
• Wait for page load.
class CommonMethods:
@contextmanager
def wait_for_page_load(self, timeout=TIMEOUT):
old_element = self.browser.find_element_by_tag_name('html')
yield
WebDriverWait(self.browser, timeout).until(EC.staleness_of(old_element))
# Wait until ready state is complete
self.wait_until(
lambda _: self.browser.execute_script('return document.readyState') == 'complete'
)
...
with self.wait_for_page_load():
self.browser.get(self.live_server_url + '/dashboard/entry/'
self.browser.get(self.live_server_url + '/dashboard/entry/')
?
Fluently wait
• Simpler explicit wait.
class CommonMethods:
...
def wait_until(self, condition):
WebDriverWait(self.browser, TIMEOUT).until(condition)
element = self.wait_until(
EC.element_to_be_clickable((By.ID, 'myDynamicElement'))
)
element = WebDriverWait(ff, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
Make your own useful scripts
class CommonMethods:
...
def clear_input(self, element):
self.browser.execute_script('arguments[0].value = ""', element)
def click_button(self, element):
self.browser.execute_script('arguments[0].click()', element)
self.clear_input(self.elm['email_input'])
Using send_keys(str) appends str, not replacing
Using selenium’s click() sometimes not working (animated buttons, …)
self.click_button(self.elm['submit_button'])
Separate page implementation
from test codes
CommonMethods
WebPageBase FunctionalTestBase
LogInPage
SignupPage
…
LogInTest
SignupProcessTest
…
/accounts/login/
/accounts/signup/
Web page classes
class LogInPage(WebPageBase):
def __init__(self, browser):
super(LogInPage, self).__init__(browser)
self.elm.update({
'email_input': browser.find_element_by_name('email'),
'pwd_input': browser.find_element_by_name('password'),
'submit_button': browser.find_element_by_css_selector('fieldset paper-button'),
...
})
def login(self, email, password):
self.elm['email_input'].send_keys(email)
self.elm['pwd_input'].send_keys(password)
with self.wait_for_page_load():
self.click_button(self.elm['submit_button'])
def click_signup_button(self):
with self.wait_for_page_load():
self.click_button(self.elm['signup_link'])
def click_forgot_password_button(self):
with self.wait_for_page_load():
self.click_button(self.elm['forgot_pwd'])
class SignUpPage(WebPageBase):
...
pre-define static elements
modularize representative features
Test classes using web page
classes
class LoginTest(FunctionalTestBase):
def test_user_login(self):
# Store login count of the user
user = get_user_model().objects.get(username='einstein')
logincount = user.profile.logincount
# Visit login page and login
with self.wait_for_page_load():
self.browser.get(self.live_server_url)
login_page = LogInPage(self.browser)
login_page.login('einstein@lablup.com', '0000')
# Check login count is increased by 1
user = get_user_model().objects.get(username='einstein')
self.assertEqual(user.profile.logincount, logincount + 1)
# Check expected url
target_url = self.live_server_url + '/dashboard/'
self.assertEqual(self.browser.current_url, target_url)
class SignupProcessTest(FunctionalTestBase):
def test_user_signup(self):
# User clicks signup button at login page
with self.wait_for_page_load():
self.browser.get(self.live_server_url)
login_page = LogInPage(self.browser)
login_page.click_signup_button()
...
use web page classes / methods
Summary
• Using Selenium for Django functional tests.
• Wait is important in Selenium.
•Use explicit wait.
• Automate tests on AWS EC2.
• Give structure to your tests.
• Make your useful scripts.
Thank you!
• Staffs of APAC PyCon 2016
• … And ALL ofYOU!
http://www.lablup.com/
https://codeonweb.com/
https://kid.codeonweb.com/

Contenu connexe

Tendances

Testing for Pragmatic People
Testing for Pragmatic PeopleTesting for Pragmatic People
Testing for Pragmatic People
davismr
 
Appsec usa2013 js_libinsecurity_stefanodipaola
Appsec usa2013 js_libinsecurity_stefanodipaolaAppsec usa2013 js_libinsecurity_stefanodipaola
Appsec usa2013 js_libinsecurity_stefanodipaola
drewz lin
 

Tendances (20)

Automated Testing with Ruby
Automated Testing with RubyAutomated Testing with Ruby
Automated Testing with Ruby
 
Introduction to Protractor
Introduction to ProtractorIntroduction to Protractor
Introduction to Protractor
 
Java script unit testing
Java script unit testingJava script unit testing
Java script unit testing
 
Protractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applicationsProtractor framework – how to make stable e2e tests for Angular applications
Protractor framework – how to make stable e2e tests for Angular applications
 
Selenium
SeleniumSelenium
Selenium
 
Kiss PageObjects [01-2017]
Kiss PageObjects [01-2017]Kiss PageObjects [01-2017]
Kiss PageObjects [01-2017]
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
 
Class-based views with Django
Class-based views with DjangoClass-based views with Django
Class-based views with Django
 
Testing for Pragmatic People
Testing for Pragmatic PeopleTesting for Pragmatic People
Testing for Pragmatic People
 
ERRest
ERRestERRest
ERRest
 
ERRest in Depth
ERRest in DepthERRest in Depth
ERRest in Depth
 
Advanced Django
Advanced DjangoAdvanced Django
Advanced Django
 
Write Selenide in Python 15 min
Write Selenide in Python 15 minWrite Selenide in Python 15 min
Write Selenide in Python 15 min
 
Behind the curtain - How Django handles a request
Behind the curtain - How Django handles a requestBehind the curtain - How Django handles a request
Behind the curtain - How Django handles a request
 
Efficient Rails Test-Driven Development - Week 6
Efficient Rails Test-Driven Development - Week 6Efficient Rails Test-Driven Development - Week 6
Efficient Rails Test-Driven Development - Week 6
 
Appsec usa2013 js_libinsecurity_stefanodipaola
Appsec usa2013 js_libinsecurity_stefanodipaolaAppsec usa2013 js_libinsecurity_stefanodipaola
Appsec usa2013 js_libinsecurity_stefanodipaola
 
ERRest - The Next Steps
ERRest - The Next StepsERRest - The Next Steps
ERRest - The Next Steps
 
ERRest - Designing a good REST service
ERRest - Designing a good REST serviceERRest - Designing a good REST service
ERRest - Designing a good REST service
 
Efficient Rails Test Driven Development (class 3) by Wolfram Arnold
Efficient Rails Test Driven Development (class 3) by Wolfram ArnoldEfficient Rails Test Driven Development (class 3) by Wolfram Arnold
Efficient Rails Test Driven Development (class 3) by Wolfram Arnold
 
KAAccessControl
KAAccessControlKAAccessControl
KAAccessControl
 

En vedette

TOROS: Python Framework for Recommender System
TOROS: Python Framework for Recommender SystemTOROS: Python Framework for Recommender System
TOROS: Python Framework for Recommender System
Kwangseob Kim
 
Python 으로 19대 국회 뽀개기 (PyCon APAC 2016)
Python 으로 19대 국회 뽀개기 (PyCon APAC 2016)Python 으로 19대 국회 뽀개기 (PyCon APAC 2016)
Python 으로 19대 국회 뽀개기 (PyCon APAC 2016)
HONGJOO LEE
 

En vedette (13)

Ajax in Django
Ajax in DjangoAjax in Django
Ajax in Django
 
PyCon APAC 2016: Django, Flask 고민없이 개발하고 서비스하는 PaaS, IBM Bluemix
PyCon APAC 2016: Django, Flask 고민없이 개발하고 서비스하는 PaaS, IBM BluemixPyCon APAC 2016: Django, Flask 고민없이 개발하고 서비스하는 PaaS, IBM Bluemix
PyCon APAC 2016: Django, Flask 고민없이 개발하고 서비스하는 PaaS, IBM Bluemix
 
TOROS: Python Framework for Recommender System
TOROS: Python Framework for Recommender SystemTOROS: Python Framework for Recommender System
TOROS: Python Framework for Recommender System
 
Python Unittest
Python UnittestPython Unittest
Python Unittest
 
파이썬 삼총사 : Tox, Travis 그리고 Coveralls
파이썬 삼총사 : Tox, Travis 그리고 Coveralls파이썬 삼총사 : Tox, Travis 그리고 Coveralls
파이썬 삼총사 : Tox, Travis 그리고 Coveralls
 
Python의 계산성능 향상을 위해 Fortran, C, CUDA-C, OpenCL-C 코드들과 연동하기
Python의 계산성능 향상을 위해 Fortran, C, CUDA-C, OpenCL-C 코드들과 연동하기Python의 계산성능 향상을 위해 Fortran, C, CUDA-C, OpenCL-C 코드들과 연동하기
Python의 계산성능 향상을 위해 Fortran, C, CUDA-C, OpenCL-C 코드들과 연동하기
 
[2016 데이터 그랜드 컨퍼런스] 2 5(빅데이터). 유비원 비정형데이터 중심의 big data 활용방안
[2016 데이터 그랜드 컨퍼런스] 2 5(빅데이터). 유비원 비정형데이터 중심의 big data 활용방안[2016 데이터 그랜드 컨퍼런스] 2 5(빅데이터). 유비원 비정형데이터 중심의 big data 활용방안
[2016 데이터 그랜드 컨퍼런스] 2 5(빅데이터). 유비원 비정형데이터 중심의 big data 활용방안
 
Continuous Integration Testing in Django
Continuous Integration Testing in DjangoContinuous Integration Testing in Django
Continuous Integration Testing in Django
 
Python 테스트 시작하기
Python 테스트 시작하기Python 테스트 시작하기
Python 테스트 시작하기
 
딥러닝과 강화 학습으로 나보다 잘하는 쿠키런 AI 구현하기 DEVIEW 2016
딥러닝과 강화 학습으로 나보다 잘하는 쿠키런 AI 구현하기 DEVIEW 2016딥러닝과 강화 학습으로 나보다 잘하는 쿠키런 AI 구현하기 DEVIEW 2016
딥러닝과 강화 학습으로 나보다 잘하는 쿠키런 AI 구현하기 DEVIEW 2016
 
Python 으로 19대 국회 뽀개기 (PyCon APAC 2016)
Python 으로 19대 국회 뽀개기 (PyCon APAC 2016)Python 으로 19대 국회 뽀개기 (PyCon APAC 2016)
Python 으로 19대 국회 뽀개기 (PyCon APAC 2016)
 
텐서플로우 설치도 했고 튜토리얼도 봤고 기초 예제도 짜봤다면 TensorFlow KR Meetup 2016
텐서플로우 설치도 했고 튜토리얼도 봤고 기초 예제도 짜봤다면 TensorFlow KR Meetup 2016텐서플로우 설치도 했고 튜토리얼도 봤고 기초 예제도 짜봤다면 TensorFlow KR Meetup 2016
텐서플로우 설치도 했고 튜토리얼도 봤고 기초 예제도 짜봤다면 TensorFlow KR Meetup 2016
 
지적 대화를 위한 깊고 넓은 딥러닝 PyCon APAC 2016
지적 대화를 위한 깊고 넓은 딥러닝 PyCon APAC 2016지적 대화를 위한 깊고 넓은 딥러닝 PyCon APAC 2016
지적 대화를 위한 깊고 넓은 딥러닝 PyCon APAC 2016
 

Similaire à Automating Django Functional Tests Using Selenium on Cloud

Top100summit 谷歌-scott-improve your automated web application testing
Top100summit  谷歌-scott-improve your automated web application testingTop100summit  谷歌-scott-improve your automated web application testing
Top100summit 谷歌-scott-improve your automated web application testing
drewz lin
 

Similaire à Automating Django Functional Tests Using Selenium on Cloud (20)

Selenium training
Selenium trainingSelenium training
Selenium training
 
Improving Your Selenium WebDriver Tests - Belgium testing days_2016
Improving Your Selenium WebDriver Tests - Belgium testing days_2016Improving Your Selenium WebDriver Tests - Belgium testing days_2016
Improving Your Selenium WebDriver Tests - Belgium testing days_2016
 
Testing Ext JS and Sencha Touch
Testing Ext JS and Sencha TouchTesting Ext JS and Sencha Touch
Testing Ext JS and Sencha Touch
 
Testing mit Codeception: Full-stack testing PHP framework
Testing mit Codeception: Full-stack testing PHP frameworkTesting mit Codeception: Full-stack testing PHP framework
Testing mit Codeception: Full-stack testing PHP framework
 
Writing automation tests with python selenium behave pageobjects
Writing automation tests with python selenium behave pageobjectsWriting automation tests with python selenium behave pageobjects
Writing automation tests with python selenium behave pageobjects
 
Selenium
SeleniumSelenium
Selenium
 
Selenium
SeleniumSelenium
Selenium
 
Protractor Tutorial Quality in Agile 2015
Protractor Tutorial Quality in Agile 2015Protractor Tutorial Quality in Agile 2015
Protractor Tutorial Quality in Agile 2015
 
Selenium testing - Handle Elements in WebDriver
Selenium testing - Handle Elements in WebDriver Selenium testing - Handle Elements in WebDriver
Selenium testing - Handle Elements in WebDriver
 
Web driver training
Web driver trainingWeb driver training
Web driver training
 
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
Carmen Popoviciu - Protractor styleguide | Codemotion Milan 2015
 
jQuery Performance Tips and Tricks
jQuery Performance Tips and TricksjQuery Performance Tips and Tricks
jQuery Performance Tips and Tricks
 
full-stack-webapp-testing-with-selenium-and-rails.pdf
full-stack-webapp-testing-with-selenium-and-rails.pdffull-stack-webapp-testing-with-selenium-and-rails.pdf
full-stack-webapp-testing-with-selenium-and-rails.pdf
 
selenium.ppt
selenium.pptselenium.ppt
selenium.ppt
 
Top100summit 谷歌-scott-improve your automated web application testing
Top100summit  谷歌-scott-improve your automated web application testingTop100summit  谷歌-scott-improve your automated web application testing
Top100summit 谷歌-scott-improve your automated web application testing
 
Mastering Test Automation: How To Use Selenium Successfully
Mastering Test Automation: How To Use Selenium SuccessfullyMastering Test Automation: How To Use Selenium Successfully
Mastering Test Automation: How To Use Selenium Successfully
 
Automation - web testing with selenium
Automation - web testing with seleniumAutomation - web testing with selenium
Automation - web testing with selenium
 
Behave manners for ui testing pycon2019
Behave manners for ui testing pycon2019Behave manners for ui testing pycon2019
Behave manners for ui testing pycon2019
 
Escaping Test Hell - ACCU 2014
Escaping Test Hell - ACCU 2014Escaping Test Hell - ACCU 2014
Escaping Test Hell - ACCU 2014
 
selenium.ppt
selenium.pptselenium.ppt
selenium.ppt
 

Dernier

%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
masabamasaba
 

Dernier (20)

%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 

Automating Django Functional Tests Using Selenium on Cloud

  • 1. Automating Django FunctionalTests Using Selenium on Cloud Jonghyun Park, Lablup Inc. 2016/08/14 (Sun) @PyCon APAC 2016
  • 2. Contents and target audience •How to functional tests on Django using Selenium. • Running functional tests automatically on AWS EC2. • And some tips on writing functional tests (if time permits). • Target audience • Python beginners - intermediates. • Who have written some tests in Python/Django • … but not much.
  • 3. About speaker • Physics (~4 yr) • Single-molecule Biophysics (~8 yr) • Optical microscope • DNA, protein • IT newbie (~1.2 yr) • HTML, CSS, Javascript, Polymer (Google) • Python-Django
  • 5. CodeTest General remarks about code testing Tests on CodeOnWeb
  • 6. Test code • Code that tests code. def login(username, password, ...): ... if success: return True else: return False def test_login(): result = login('test', '1' , ...) assertTrue(result) Test login.py test_login.py
  • 7. Why tests code? • How do we know our code is okay even if we are messing around all the parts of the code? • Ensure minimal code integrity when refactoring. • Man cannot test all features by hand. • Pre-define requirements for a feature.
  • 9. Writing tests is good for newbie • Can understand the logic of each function/module • … w/o destroying real service whatever you do. • Defeat bugs & improves codes, if you are lucky. https://goo.gl/sU2D2M There are stupid codes, but not stupid test codes! like me
  • 10. Kinds of tests for CodeOnWeb • Unit tests • Test of independent unit of behavior. • e.g., function, class method. • Test layer: model / form / view. • Functional tests • Test of independent piece of functionality. • May test many functions or methods. • Test of actual user interaction on the web browser. lenium
  • 11. Using Selenium Functional testing using selenium with Django
  • 12. Selenium • Browser emulator. • Automate user interaction on the browser. • Can be utilized for testing … and other things. python manage.py test functional_tests.test_login_registration .LoginTest Browser (Firefox, Chrome, …) Selenium Webdriver
  • 13. Test scheme using Selenium Install Selenium pip install selenium Get browser through webdriver browser = webdriver.Firefox() Visit web page browser.get(url) Do whatever you want Test response is expected browser.find_element_by_id( 'lst-ib').send_keys('haha') self.assertEqual(...) self.assertTrue(...)
  • 14. Example: automating googling import time from selenium import webdriver from selenium.webdriver.common.keys import Keys # Get browser through webdriver browser = webdriver.Firefox() # Visit Google! browser.get('https://google.com/') # Enter keyword and enter inp = browser.find_element_by_id('lst-ib') inp.send_keys('PyCon 2016') inp.send_keys(Keys.RETURN) # Just wait a little time.sleep(3) # Close browser window browser.quit() python functional_tests/test_pycon_google1.py This is not a test case!
  • 15. Convert to Django’s test case import time from django.contrib.staticfiles.testing import StaticLiveServerTestCase from selenium import webdriver from selenium.webdriver.common.keys import Keys class GoogleTest(StaticLiveServerTestCase): def setUp(self): self.browser = webdriver.Firefox() self.browser.set_window_size(1024, 768) def tearDown(self): time.sleep(3) self.browser.quit() def test_google_search(self): self.browser.get('https://google.com/') inp = self.browser.find_element_by_id('lst-ib') inp.send_keys('PyCon 2016') inp.send_keys(Keys.RETURN) live django server + collect static files python functional_tests/test_pycon_google2.py(X) python manage.py test functional_tests.test_pycon_google2(O)
  • 16. Finding elements browser.find_element_by_id('loginForm') .find_element_by_css_selector('input[name="username"]') .find_element_by_name('username') .find_element_by_class_name('login') .find_element_by_tag_name('input') .find_element_by_tag_link_text('Go to Google') .find_element_by_tag_partial_link_text('Go to') .find_element_by_xpath('//form[@id=" loginForm "]') <html> <body> <form id="loginForm" class="login"> <input name="username" type="text" /> <input name="password" type="password" /> <input name="continue" type="submit" value="Login" /> </form> <a href=”https://google.com/">Go to Google</a> </body> <html> browser.find_elements_by_id('loginForm') ...
  • 17. Interacting with elements item = browser.find_element_by_id('entry-item') item.click() ui_type = item.get_attribute('ui-type') browser.execute_script( 'arguments[0].setAttribute("disabled", "true")', item, ) browser.execute_script( 'arguments[0].querySelector("paper-menu").selected = arguments[1]', item, '2' ) Not that difficult if you know Javascript.
  • 18. Let’s write a login test def test_user_login(self): # Store login count of the user user = get_user_model().objects.get(username='einstein') logincount = user.profile.logincount # visit root url ('/') self.browser.get(self.live_server_url) # Try to login with email and password self.browser.find_element_by_name('email').send_keys('einstein@lablup.com') self.browser.find_element_by_name('password').send_keys('1') self.browser.find_element_by_css_selector('fieldset paper-button').click() # Confirm login count is increased by 1 user = get_user_model().objects.get(username='einstein') self.assertEqual(user.profile.logincount, logincount + 1) # Check visit correct url target_url = self.live_server_url + '/accounts/profile/usertype/' self.assertEqual(self.browser.current_url, target_url) python manage.py test functional_tests.test_pycon_login
  • 19. Waits in Selenium Waiting is very important
  • 20. Selenium, the beauty of waiting • Wait what? • Page loading • Elements loading • Elements visibility • Ajax response • DB operation • … https://goo.gl/5ykwc4
  • 21. Broken login example def test_user_login(self): # Store login count of the user user = get_user_model().objects.get(username='einstein') logincount = user.profile.logincount # visit root url ('/') self.browser.get(self.live_server_url) # Try to login with email and password self.browser.find_element_by_name('email').send_keys('einstein@lablup.com') self.browser.find_element_by_name('password').send_keys('1') self.browser.find_element_by_css_selector('fieldset paper-button').click() # Confirm login count is increased by 1 user = get_user_model().objects.get(username='einstein') self.assertEqual(user.profile.logincount, logincount + 1) # Check visit correct url target_url = self.live_server_url + '/accounts/profile/usertype/' self.assertEqual(self.browser.current_url, target_url) python manage.py test functional_tests.test_pycon_login
  • 22. Selenium do not wait automatically login.html submit() views.py … user.profile.logincount += 1 user.profile.save() ... render logged_in.html logged_in.html test_pycon_login.py user.profile.logincount Which one is faster?
  • 23. Selenium do not wait automatically browser.get("http://www.google.com") Dependent on several factors, including the OS/Browser combination, WebDriver may or may not wait for the page to load.
  • 24. Waiting methods in Selenium • Implicit wait • Explicit wait • Stupid wait • It is highly un-recommended to wait for specific amounts of time. • If target is loaded in 5 s, we waste the remaining time. • If target is not loaded in 5 s, the test fails (slow system). import time time.sleep(5) Provided by Selenium
  • 25. Implicit wait • Official DOC: • Easy to use, global effect. • Applies only for element waiting. An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available.The default setting is . Once set, the implicit wait is set for the life of theWebDriver object instance. browser = webdriver.Firefox() browser.implicitly_wait(10) # in seconds browser.get("http://somedomain/url_that_delays_loading") myDynamicElement = browser.find_element_by_id("myDynamicElement")
  • 26. Implicit wait • Waiting behavior is determined on the “remote” side of the webdriver. • Different waiting behavior on different OS, browser, versions, etc. • Return element immediately • Wait until timeout • … def implicitly_wait(self, time_to_wait): self.execute(Command.IMPLICIT_WAIT, {'ms': float(time_to_wait) * 1000}) WebDriver RemoteConnection.execute() Browser (Firefox, Chrome, …) Selenium Webdriver
  • 27. Explicit wait • Official DOC: • A little messy, local effect. An explicit wait is code you define to wait for a certain condition to occur before proceeding further in the code. …WebDriverWait in combination with ExpectedCondition is one way this can be accomplished. from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait import selenium.webdriver.support.expected_conditions as EC ff = webdriver.Firefox() ff.get("http://somedomain/url_that_delays_loading") try: element = WebDriverWait(ff, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement")) ) finally: ff.quit()
  • 28. Explicit wait • Highly flexible (variety of expected conditions) EC.title_is(...) .title_contains(...) .presence_of_element_located(...) .visibility_of_element_located(...) .visibility_of(...) .presence_of_all_elements_located(...) .text_to_be_present_in_element(...) .text_to_be_present_in_element_value(...) .frame_to_be_available_and_switch_to_it(...) .invisibility_of_element_located(...) .element_to_be_clickable(...) .staleness_of(...) .element_to_be_selected(...) .element_located_to_be_selected(...) .element_selection_state_to_be(...) .element_located_selection_state_to_be(...) .alert_is_present(...)
  • 29. Explicit wait • Highly flexible (not limited for waiting element) • Waiting is controlled on the “local” side. • Defined behavior. def until(self, method, message=''): end_time = time.time() + self._timeout while(True): try: value = method(self._driver) if value: return value except self._ignored_exceptions: pass time.sleep(self._poll) if(time.time() > end_time): break raise TimeoutException(message) condition = lambda _: self.browser.execute_script('return document.readyState') == 'complete' WebDriverWait(self.browser, 30).until(condition) Browser (Firefox, Chrome, …) Selenium Webdriver
  • 30. Use explicit wait • Use explicit wait! • In good conditions (OS, browser, version), implicit wait can simplify test codes. • Be aware that the condition may change in the future. • I think implicit wait is not very stable way to go. • Never use stupid wait. • Except in a very limited cases (like presentation?).
  • 31. RunningTests on Cloud (AWS EC2) Functional tests: automatically once a day
  • 32. Run selenium on AWS • No screen • Virtual display • Slow machine (low cost) • Give timeout generously • That’s all!
  • 33. Run selenium on AWS # Install headless java sudo apt-get install openjdk-6-jre-headless # Fonts sudo apt-get install xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic # Headless X11 magic is here sudo apt-get install xvfb # We still demand X11 core sudo apt-get install xserver-xorg-core # Firefox installation sudo apt-get install firefox # Download Selenium server wget http://selenium.googlecode.com/files/selenium-server-standalone-2.31.0.jar # Run Selenium server Xvfb :0 -screen 0 1440x900x16 2>&1 >/dev/null & export DISPLAY=:0 nohup xvfb-run java -jar selenium-server-standalone-2.53.0.jar > selenium.log & http://goo.gl/GRbztO + crontab
  • 34. Test automation for CodeOnWeb Unit tests Functional tests Local1 Test server (on EC2) git commit; git push Actual codes Github Github-Auto-Deploy (listen hook run scripts) hook git pull post-merge hook Run DB migration Run unit tests listen err no err Error posting script Run functional tests errno err Unit tests Functional tests Local2 git commit; git push Actual codes once a day comment on issue …
  • 35. Slack integration is also possible
  • 36. SomeTips Most of them is on the web.
  • 37. Faster password hasher • Use fastest password hasher (MD5) in testing. • Django’s default: PBKDF2 algorithm with SHA256 hash. • It’s more secure, but quite slow. • In our case, this reduces the test running time by • half (for unit tests). • ~10% (for functional tests). • Never use this in production server. PASSWORD_HASHERS = [ 'django.contrib.auth.hashers.MD5PasswordHasher', ] settings.py
  • 38. Shorter login from django.conf import settings from django.contrib.auth import get_user_model, BACKEND_SESSION_KEY, SESSION_KEY, HASH_SESSION_KEY from django.contrib.sessions.backends.db import SessionStore def login_browser(self, username='einstein'): # Set fake session user = get_user_model().objects.get(username=username) session = SessionStore() session[SESSION_KEY] = user.pk session[BACKEND_SESSION_KEY] = 'django.contrib.auth.backends.ModelBackend' session[HASH_SESSION_KEY] = user.get_session_auth_hash() session.save() # To set cookies, the browser should visit a page (due to same origin policy). # It is faster to visit dummy page than login page itself. self.browser.get(self.live_server_url + '/selenium_dummy') self.browser.add_cookie({ 'name': settings.SESSION_COOKIE_NAME, 'value': session.session_key, 'secure': False, 'path': '/' }) Tests for logged-in user is requred.
  • 39. Fluently wait • Wait for page load. class CommonMethods: @contextmanager def wait_for_page_load(self, timeout=TIMEOUT): old_element = self.browser.find_element_by_tag_name('html') yield WebDriverWait(self.browser, timeout).until(EC.staleness_of(old_element)) # Wait until ready state is complete self.wait_until( lambda _: self.browser.execute_script('return document.readyState') == 'complete' ) ... with self.wait_for_page_load(): self.browser.get(self.live_server_url + '/dashboard/entry/' self.browser.get(self.live_server_url + '/dashboard/entry/') ?
  • 40. Fluently wait • Simpler explicit wait. class CommonMethods: ... def wait_until(self, condition): WebDriverWait(self.browser, TIMEOUT).until(condition) element = self.wait_until( EC.element_to_be_clickable((By.ID, 'myDynamicElement')) ) element = WebDriverWait(ff, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement")) )
  • 41. Make your own useful scripts class CommonMethods: ... def clear_input(self, element): self.browser.execute_script('arguments[0].value = ""', element) def click_button(self, element): self.browser.execute_script('arguments[0].click()', element) self.clear_input(self.elm['email_input']) Using send_keys(str) appends str, not replacing Using selenium’s click() sometimes not working (animated buttons, …) self.click_button(self.elm['submit_button'])
  • 42. Separate page implementation from test codes CommonMethods WebPageBase FunctionalTestBase LogInPage SignupPage … LogInTest SignupProcessTest … /accounts/login/ /accounts/signup/
  • 43. Web page classes class LogInPage(WebPageBase): def __init__(self, browser): super(LogInPage, self).__init__(browser) self.elm.update({ 'email_input': browser.find_element_by_name('email'), 'pwd_input': browser.find_element_by_name('password'), 'submit_button': browser.find_element_by_css_selector('fieldset paper-button'), ... }) def login(self, email, password): self.elm['email_input'].send_keys(email) self.elm['pwd_input'].send_keys(password) with self.wait_for_page_load(): self.click_button(self.elm['submit_button']) def click_signup_button(self): with self.wait_for_page_load(): self.click_button(self.elm['signup_link']) def click_forgot_password_button(self): with self.wait_for_page_load(): self.click_button(self.elm['forgot_pwd']) class SignUpPage(WebPageBase): ... pre-define static elements modularize representative features
  • 44. Test classes using web page classes class LoginTest(FunctionalTestBase): def test_user_login(self): # Store login count of the user user = get_user_model().objects.get(username='einstein') logincount = user.profile.logincount # Visit login page and login with self.wait_for_page_load(): self.browser.get(self.live_server_url) login_page = LogInPage(self.browser) login_page.login('einstein@lablup.com', '0000') # Check login count is increased by 1 user = get_user_model().objects.get(username='einstein') self.assertEqual(user.profile.logincount, logincount + 1) # Check expected url target_url = self.live_server_url + '/dashboard/' self.assertEqual(self.browser.current_url, target_url) class SignupProcessTest(FunctionalTestBase): def test_user_signup(self): # User clicks signup button at login page with self.wait_for_page_load(): self.browser.get(self.live_server_url) login_page = LogInPage(self.browser) login_page.click_signup_button() ... use web page classes / methods
  • 45. Summary • Using Selenium for Django functional tests. • Wait is important in Selenium. •Use explicit wait. • Automate tests on AWS EC2. • Give structure to your tests. • Make your useful scripts.
  • 46. Thank you! • Staffs of APAC PyCon 2016 • … And ALL ofYOU! http://www.lablup.com/ https://codeonweb.com/ https://kid.codeonweb.com/

Notes de l'éditeur

  1. Good reference: http://goo.gl/j1kli4