I want to use the LiveServerTestCase class which is provided by flask-testing to test my flask application in combination with Selenium.
I tried implementing the tests the way described in the flask-testing documentation. But documentation on the LiveServerTestCase is very sparse and I always end up getting two instances of my testcases which are executed at the same time.
I ran my tests through Eclipse and PyCharm with the same behaviour.
How do I have to run/configure my tests to only get one testing instance?
This is how I setup my tests:
import unittest
import urllib2
from selenium import webdriver
from CodeLoad import app
from flask_testing import LiveServerTestCase
class flask_tests(LiveServerTestCase):
def create_app(self):
return app
def setUp(self):
self.driver = webdriver.Firefox()
def tearDown(self):
self.driver.close()
def test_0_server_is_up_and_running(self):
response = urllib2.urlopen(self.get_server_url())
self.assertEqual(response.code, 200)
if __name__ == '__main__':
unittest.main()
Because of a bug.
https://github.com/jarus/flask-testing/issues/33
Try turning DEBUG off
Related
I am writing automated UI tests for my Flask app using Selenium and LiveServerTestCase from Flask testing.
This is how I have everything set up:
conftest.py
import pytest
from selenium import webdriver
#pytest.yield_fixture(scope="session")
def chrome_browser():
browser = webdriver.Chrome()
yield browser
browser.quit()
test_main_page.py
from app import create_app
from flask_testing import LiveServerTestCase
import multiprocessing
class TestMainPage(LiveServerTestCase):
multiprocessing.set_start_method("fork")
def create_app(self):
app = create_app()
app.config['TESTING'] = True
app.config.update(LIVESERVER_PORT=9898)
return app
def test_main_page(self, chrome_browser):
driver = chrome_browser
assert 1 == 1
Running Pytest giving me the following exception:
FAILED test_main_page.py::TestMainPage::test_main_page - TypeError: test_main_page() missing 1 required positional argument: 'chrome_browser'
When removing the LiveServerTestCase from the TestMainPage class, the fixture chrome_browser is working just fine.
How can I use both LiveServerTestCase and Pytest fixtures?
Thanks
I am somewhat of a beginner in python, i am currently writing a suite of test cases with selenium webdriver using unittest; i have also found a lot of useful answers here, but it's time a ask my first question, i have struggled a lot with this and cannot find a proper answer, so any help is greatly appreciated:
For short, i have a suite of multiple tests cases, and in each case the first step is always ".get('Some URL')"; i have written these test cases for a single environment, but i would like to be able to select the URL on which all tests will be executed. In the example below i called the "access_url" method with a specific environment, but i need to do this for all of my scenarios at once, is it possible to do this from where i execute the .py file (e.g. "python example.py")? or to pass it in the .run() method when i select what suite to run?
import HTMLTestRunner
from selenium import webdriver
import unittest
This is a custom class used to create the 'access_url' method
def MyClass(object):
def __init__(self, driver):
self.driver = driver
def access_url(self, URL):
if URL == 'environment 1':
self.driver.get('https://www.google.com/')
elif URL == 'environment 2':
self.driver.get('https://example.com/')
In the classes i use to write test cases the first step is always 'access URL'
class TestScenario01(unittest.TestCase):
def setUp(self):
[...]
def test_01_access(self):
MyClass(self.driver).access_url(URL='environment 2')
def test_02(self):
[...]
def test_03(self):
[...]
In order to run the tests i place them all in a suite and use .run() on them
tc_scenario01 = unittest.TestLoader().loadTestsFromTestCase(TestScenario01)
test_suite = unittest.TestSuite([tc_scenario01])
HTMLReporterCustom.HTMLTestRunner().run(test_suite)
Finally, in order to execute the script i type the follwoing line in CMD: 'python example_file.py
As i mentioned above, all i want to do is to be able to somehow pass the URL one time to all test cases that call the "access_url()" method. Thanks!
You can maintain environment properties in separate config file.
config.py
DEFAULT_ENVIRONMENT='environment1'
URL = {
'environment1': 'https://www.google.com/',
'environment2': 'https://example.com/'
}
Your Class,
from package import config
def MyClass(object):
def __init__(self, driver):
self.driver = driver
def access_url(self):
self.driver.get(config.URL[config.DEFAULT_ENVIRONMENT])
Then test class will be as expected,
class TestScenario01(unittest.TestCase):
def setUp(self):
[...]
def test_01_access(self):
MyClass(self.driver).access_url()
def test_02(self):
[...]
def test_03(self):
[...]
While running test you can change,
main.py
from package import config
config.DEFAULT_ENVIRONMENT = 'enviroment2'
tc_scenario01 = unittest.TestLoader().loadTestsFromTestCase(TestScenario01)
test_suite = unittest.TestSuite([tc_scenario01])
HTMLReporterCustom.HTMLTestRunner().run(test_suite)
You can also pass the environment name while running python main.py.
main.py
if __name__ == '__main__':
config.DEFAULT_ENVIRONMENT = sys.argv[1] if len(sys.argv) > 2 else 'dev'
tc_scenario01 = unittest.TestLoader().loadTestsFromTestCase(TestScenario01)
test_suite = unittest.TestSuite([tc_scenario01])
HTMLReporterCustom.HTMLTestRunner().run(test_suite)
Below is displayed my test class . This is good test when i call it once - python3 main.py.
There is a problem if I want this test run for example 100 times. How to do that?
When I try call by pytest there are warnings sth like this:
main.py::TestLoginPage::test_login_invalid_credentials
/home/-----/.local/lib/python3.5/site-packages/pytest_repeat.py:31: UserWarning: Repeating unittest class tests not supported
"Repeating unittest class tests not supported")
main.py::TestLoginPage::test_login_valid_credentials
/home/-----/.local/lib/python3.5/site-packages/pytest_repeat.py:31: UserWarning: Repeating unittest class tests not supported
"Repeating unittest class tests not supported")
This is my test class - test_login_page.py
import unittest
from selenium import webdriver
from tests.test_driver import TestDriver
from pages.login_page import LoginPage
class TestLoginPage(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.page_url = LoginPage.login_url
cls.webdriver = webdriver
TestDriver.setUp(cls, cls.page_url)
cls.page = LoginPage(cls.webdriver)
cls.option = 1
def __init_test_method(self):
# [TS001].Check if page is loaded correctly
self.assertTrue(self.page.check_page_loaded_correctly)
# [TS002].Check button contains 'login' text
self.assertEqual(self.page.get_button_text(), 'Login')
# TC001
def test_login_valid_credentials(self):
"""Test login with valid credentials"""
self.__init_test_method()
# [TS003].Clear form, fill with correct data and submit
self.assertEqual(self.page.login_process(self.option), 'Complexes')
# TC002 (invalid password) & TC003 (invalid username)
def test_login_invalid_credentials(self):
"""Test login with invalid credentials"""
for option in range(2, 4):
self.__init_test_method()
self.assertTrue(self.page.login_process(option))
#classmethod
def tearDownClass(cls):
cls.webdriver.quit()
This is main which I run all tests from console - main.py
import unittest
import os
import sys
cwd = os.getcwd()
sys.path.append(cwd)
from tests.test_login_page import TestLoginPage
if __name__ == '__main__':
unittest.main()
If you want to run your tests over and over, I would suggest you use ddt or data driven tests. You can find the documentation for complete usage here.
You will decorate your test class with ddt and your test method with file_data or data to pass in unique test parameters.
This will allow you to feed new test parameters for each iteration of your test and will cycle through and run the same test method for however many times you need.
Here is an example of how I use it:
from ddt import ddt, file_data
#ddt
class MyTestClass(unittest.TestCase):
#file_data('test_parameter_file.json')
def some_test_method1(self, test_package):
Some test method
I have the different test parameters in the test_parameter_file.json file and my test method is run for each parameter in the file.
I have multiple tests inside one test case but I am noticing that it is only running the first test
import unittest
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.support.ui import WebDriverWait
class Test(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.base_url = "http://www.example.com/"
def test_Google(self):
driver = self.driver
driver.implicitly_wait(10)
driver.get(self.base_url)
def fill_contact(self):
driver.find_element_by_xpath('//a[contains(.,"Contact")]').click()
driver.implicitly_wait(10)
driver.find_element_by_xpath('//input[#type="submit"][#value="Send"]').click()
# def tearDown(self):
# self.driver.quit()
if __name__ == "__main__":
unittest.main()
Whenever I run this it only runs
def test_Google(self)
and nothing after that. am I doing something wrong?
Methods must begin with 'test' to be automatically run.
Per the docs:
A testcase is created by subclassing unittest.TestCase. The three
individual tests are defined with methods whose names start with the
letters test. This naming convention informs the test runner about
which methods represent tests. (my emphasis)
The TestLoader is responsible for loading test and returning them wrapped in a TestSuite. It uses this method to identify tests:
class TestLoader(object):
testMethodPrefix = 'test'
def getTestCaseNames(self, testCaseClass):
"""Return a sorted sequence of method names found within testCaseClass
"""
def isTestMethod(attrname, testCaseClass=testCaseClass,
prefix=self.testMethodPrefix):
return attrname.startswith(prefix) and \
hasattr(getattr(testCaseClass, attrname), '__call__')
testFnNames = filter(isTestMethod, dir(testCaseClass))
...
Thus, the attrname.startswith(prefix) checks if the method name begins with 'test'.
As an alternative to what #unubtu noted:
you can use a nose test runner and mark a method with #istest decorator:
from nose.tools import istest
class Test(unittest.TestCase):
...
#istest
def fill_contact(self):
driver.find_element_by_xpath('//a[contains(.,"Contact")]').click()
driver.implicitly_wait(10)
driver.find_element_by_xpath('//input[#type="submit"][#value="Send"]').click()
Besides, here is a pretty good overview of the unittest test discovery:
How does Python's unittest module detect test cases?
I have started using nose to run tests. I discovered the multiprocessing plugin has a timeout, that I can change on the command line.
Is there a way to extend the timeout for individual tests (in the test code) so I don't have a massive global timeout?
I haven't any experience with the multiprocessing plugin but if you subclass the plugin with something like this:
from nose.plugins.multiprocess import MultiProcess
PLUGIN = None
class TimeoutMultiProcess(MultiProcess):
def configure(self, options, conf):
global PLUGIN
PLUGIN = self
super(TimeoutMultiProcess, self).configure(options, conf)
if not self.enabled:
return
then you can create your own test running script like:
import unittest
class TestA(unittest.TestCase):
def setUp(self):
from runtest import PLUGIN
print PLUGIN.config.multiprocess_timeout
def test_a(self):
pass
def test_b(self):
pass
if __name__ == '__main__':
from runtest import TimeoutMultiProcess
import nose
nose.main(addplugins=[TimeoutMultiProcess()], defaultTest="./test.py")
You'll be able to change the config.multiprocess_timeout to different values within your tests. I'm not sure if it will work for you, but it's worth a shot.