Django automated runserver and functional test
Question:
Im trying to use invoke module to automate my django functional tests, but I realised as the runserver command is rolling on my script waits until its finished to run the next command
from invoke import task
@task
def runserver(c):
c.run('python manage.py runserver')
@task
def test(c):
c.run('python functional_test.py')
@task(runserver, test)
def build(c):
pass
I wanted to run both simultaneously, maybe with async or threding but cant figure out how.
Answers:
I ended up using the following code, with the idea @Nealium gave but with Pebble module:
from time import sleep
from invoke import task
from pebble import concurrent
import os
@task
def runserver(c,ip=None):
if ip:
ip_addr = ip
else:
ip_addr = None
@concurrent.thread
def build(c):
if ip_addr:
c.run(f'python manage.py runserver {ip_addr}:8091')
else:
c.run('python manage.py runserver')
sleep(3)
@concurrent.thread
def start():
with open('build.txt','w') as file:
file.write("Build done")
c.run('python functional_test.py')
build_future = build()
start_future = start()
build_done = False
while not build_done:
sleep(1)
try:
with open('build.txt', 'r') as file:
content = file.read()
if 'Build done' in content:
build_future.cancel()
build_done = True
except:
pass
os.remove('build.txt')
start_future.result()
- Like this we can just call in terminal "invoke runserver" or "inv
runserver" (or change it to "build" if you like) and it will do what
it has to do and finish the test+server. I had to do the "build.txt"
file because there’s two terminals (django server and the test) and one
needed to know when the other was up.
- We can also pass –ip arg, like: "invoke runserver –ip=0.0.0.0", the
port its fixed but you got the idea
EDIT 1: Turns out Django already provided want I wanted with LiveServerTestCase class. I just didnt want to open two terminals (one to run the server locally and another to type "python manage.py test") as I intend to make a CI workflow
from django.test import LiveServerTestCase
class LoginViewTest(LiveServerTestCase):
def setUp(self):
options = Options()
options.add_argument('-headless')
manager = GeckoDriverManager().install()
driver = webdriver.Firefox(options=options, service=FirefoxService(manager))
self.driver = driver
self.user = User.objects.create_user(
username='testuser',
email='[email protected]',
password='testpassword'
)
def tearDown(self):
self.driver.quit()
def test_login_sucess(self):
#Trying to reach the login page
self.driver.get(self.live_server_url + '/login')
#Assert login title is correct
self.assertEqual(self.driver.title,'Login')
#[... continues test]
Im trying to use invoke module to automate my django functional tests, but I realised as the runserver command is rolling on my script waits until its finished to run the next command
from invoke import task
@task
def runserver(c):
c.run('python manage.py runserver')
@task
def test(c):
c.run('python functional_test.py')
@task(runserver, test)
def build(c):
pass
I wanted to run both simultaneously, maybe with async or threding but cant figure out how.
I ended up using the following code, with the idea @Nealium gave but with Pebble module:
from time import sleep
from invoke import task
from pebble import concurrent
import os
@task
def runserver(c,ip=None):
if ip:
ip_addr = ip
else:
ip_addr = None
@concurrent.thread
def build(c):
if ip_addr:
c.run(f'python manage.py runserver {ip_addr}:8091')
else:
c.run('python manage.py runserver')
sleep(3)
@concurrent.thread
def start():
with open('build.txt','w') as file:
file.write("Build done")
c.run('python functional_test.py')
build_future = build()
start_future = start()
build_done = False
while not build_done:
sleep(1)
try:
with open('build.txt', 'r') as file:
content = file.read()
if 'Build done' in content:
build_future.cancel()
build_done = True
except:
pass
os.remove('build.txt')
start_future.result()
- Like this we can just call in terminal "invoke runserver" or "inv
runserver" (or change it to "build" if you like) and it will do what
it has to do and finish the test+server. I had to do the "build.txt"
file because there’s two terminals (django server and the test) and one
needed to know when the other was up. - We can also pass –ip arg, like: "invoke runserver –ip=0.0.0.0", the
port its fixed but you got the idea
EDIT 1: Turns out Django already provided want I wanted with LiveServerTestCase class. I just didnt want to open two terminals (one to run the server locally and another to type "python manage.py test") as I intend to make a CI workflow
from django.test import LiveServerTestCase
class LoginViewTest(LiveServerTestCase):
def setUp(self):
options = Options()
options.add_argument('-headless')
manager = GeckoDriverManager().install()
driver = webdriver.Firefox(options=options, service=FirefoxService(manager))
self.driver = driver
self.user = User.objects.create_user(
username='testuser',
email='[email protected]',
password='testpassword'
)
def tearDown(self):
self.driver.quit()
def test_login_sucess(self):
#Trying to reach the login page
self.driver.get(self.live_server_url + '/login')
#Assert login title is correct
self.assertEqual(self.driver.title,'Login')
#[... continues test]