For some reason, VSCode is not picking up my "test_*" file?
Here is the code:
import pytest
import requests
import responses
#responses.activate
def test_simple(api_key: str, url: str):
"""Test"""
responses.add(responses.GET, url=url+api_key,
json={"error": "not found"}, status=404)
resp = requests.get(url+api_key)
assert resp.json() == {"error": "not found"}
I've tried using CTRL+SHIFT+P and configuring tests, but this also fails, it says: Test discovery failed and Test discovery error, please check the configuration settings for the tests.
In my settings, the only thing related to pytest is: "python.testing.pytestEnabled": true.
What is going on here? My file starts with "test" and so does my function within that file?
Related
I have an azure function that depends on extras of a specific library, however it seems that Functions is ignoring the extras specified in the requirements.txt
I have specified this in the requirements.txt:
functown>=2.0.0
functown[jwt]>=2.0.0
This should install additional dependencies (python-jose in this case), however it seems like the extras are ignored by Azure functions:
No module named 'jose'. Please check the requirements.txt file for the missing module.
I also tested this locally and can confirm that for a regular pip install -r requirements.txt the extras are picked up and python-jose is indeed installed (which I can verify by import jose).
Are there special settings to be set in Azure Function or is this a bug?
Update 1:
In particular I want to install the dependencies on an extra of a python library (defined here and reqs here), which works perfectly when setting up a local environment on my system. So I assume it is not a python or requirements problem. However, it does not work when deploying to Azure Functions, leading me to assume that there is an inherent problem with Azure Functions picking up extras requirements?
I have reproduced from my end and got below results.
Test Case 1:
With the functown Python Package, I have tested in Azure Functions Python Version 3.9 Http Trigger with the below Code:
init.py:
import logging
from logging import Logger
from functown import ErrorHandler
import azure.functions as func
#ErrorHandler(debug=True, enable_logger=True)
def main(req: func.HttpRequest, logger: Logger, **kwargs) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
a = 3
b= 5
if a > b:
raise ValueError("something went wrong")
else:
print ("a is less than b")
return func.HttpResponse("Hello Pravallika, This HTTP triggered function executed successfully.", status_code=200)
requirements.txt:
azure-functions
functown
Test Case 2:
This is with the Python-Jose and Jose Libraries in Azure Functions Python v3.9 Http Trigger:
init.py:
import logging
from logging import Logger
from functown import ErrorHandler
import azure.functions as func
from jose import jwt
#ErrorHandler(debug=True, enable_logger=True)
def main(req: func.HttpRequest, logger: Logger, **kwargs) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
# Sample Code Test with functown Packages in Azure Functions Python Http Trigger
a = 3
b= 5
if a > b:
raise ValueError("something went wrong")
else:
print ("a is less than b")
# Sample Code Test with Jose, Python-Jose Packages in Azure Functions Python Http Trigger
token = jwt.encode({'key': 'value'}, 'secret', algorithm='HS256')
u'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ2YWx1ZSJ9.FG-8UppwHaFp1LgRYQQeS6EDQF7_6-bMFegNucHjmWg'
print(token)
jwt.decode(token, 'secret', algorithms=['HS256'])
{u'key': u'value'}
print(token)
return func.HttpResponse("Hello Pravallika, This HTTP triggered function executed successfully.", status_code=200)
requirements.txt:
azure-functions
functown
jose
Python-jose
Code Samples taken from the references doc1 and doc1.
For your error, I suggest you:
check the code how you imported the modules such as Jose, functown in the code as I seen similar issue in the SO #61061435 where users given code snippet for how to import the Jose Packages and the above code snippets I have provided in practical.
Make sure you have Virtual Environment installed in your Azure Functions Python Project for running the Python Functions.
Given I have added this following piece of code in conftest.py:
def pytest_addoption(parser):
parser.addoption('--environment', action='store')
I have created a Stanging.py file that has :
URL = "Some URL"
And then I launch the tesets using:
pytest --environment "Staging"
How do I then get, in a separate file, the environment option's value?
I tried in my test file:
from simple_settings import settings
and then:
print(settings.URL)
But when executed it raised:
Settings are not configured
I am trying to set up custom test library and user keyword using robot framework.
I created my test file or userkeyword file as below hello.py.
please look at the import statement in the hello.py.
if i comment out import statement(import
src.factory.serverconnectfactory) and run - test case is PASS **
if i uncomment import statement - test case is FAIL. don't know why it
fails ?
I did try to google a lot did not find any clue , even read the user guide of robot framework
not able to get any clue.
How can I import src.factory.serverconnectfactory and use it in hello.py ?
example : hello.py
from robot.api.deco import keyword
# import src.factory.serverconnectfactory ---- this line is the issue
class helloworld:
def __init__(self):
pass
#keyword("print hello")
def printhelloworld(self):
return "Hello World"
my robot test file
****** Settings ***
Library ..//..//keywordslib//helloworld.py
*** Test Cases ***
This is some test case
print hello
the error i use to get is
> Importing test library failed: ModuleNotFoundError: No module named
thanks in advance.
Solution :
Robot Framework expects Filename and classname to be same
So I tried many things (from SO and more) getting my tests running but nothing worked this is my current code:
test.py which I call to run the tests: python3 ./src/preprocess/python/test.py
import unittest
if __name__ == '__main__':
testsuite = unittest.TestLoader().discover('.')
unittest.TextTestRunner(verbosity=2).run(testsuite)
the test file looks like this:
import unittest
from scrapes.pdf import full_path_to_destination_txt_file
print(full_path_to_destination_txt_file)
class PreprocessingTest(unittest.TestCase):
def path_txt_appending(self):
self.assertEqual(full_path_to_destination_txt_file(
"test", "/usr/test"), "/usr/test/test.txt")
if __name__ == '__main__':
unittest.main(verbosity=2)
But the output is always like this:
python3 ./src/preprocess/python/test.py
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
Additional Information:
As you can see I call this not from my root directory. The test folder is in ./src/preprocess/python/test/ and has a __init__.pyfile included (there is also a init file on the level of test.py)
it would be okay for me if I have to code down all the calls for all the tests I just want to finish this
automatic search with -t does not work either so I thought the more robust method here with test.py would work...
using this framework is a requirement I have to follow
test_preprocessing.py is in the test folder and from scrapes.pdf import full_path_to_destination_txt_filescrapes is a module folder on the same level as test
When I call the single unit test directly in the command line it fails because of the relative import. But using the test.py (obviously) finds the modules.
What is wrong?
By default, unittest will only execute methods whose name starts with test:
testMethodPrefix
String giving the prefix of method names which will be interpreted as test methods. The default value is 'test'.
This affects getTestCaseNames() and all the loadTestsFrom*() methods.
from the docs.
Either change that attribute or (preferably) prefix your method name with test_.
I have the following problem.
I'd like to run tests on the local flask server before deploying to production. I use pytest for that. My conftest.py looks like that for the moment:
import pytest
from toolbox import Toolbox
import subprocess
def pytest_addoption(parser):
"""Add option to pass --testenv=local to pytest cli command"""
parser.addoption(
"--testenv", action="store", default="exodemo", help="my option: type1 or type2"
)
#pytest.fixture(scope="module")
def testenv(request):
return request.config.getoption("--testenv")
#pytest.fixture(scope="module")
def testurl(testenv):
if testenv == 'local':
return 'http://localhost:5000/'
else:
return 'https://api.domain.com/'
This allows me to test the production api by typing the command pytest and to test a local flask server by typing pytest --testenv=local
This code WORKS flawlessly.
My problem is that I have to manually instantiate the local flask server from the terminal each time I want to test locally like this:
source ../pypyenv/bin/activate
python ../app.py
Now I wanted to add a fixture that initiates a terminal in the background at the beginning of the tests and closes the server down after having finished testing. After a lot of research and testing, I still cannot get it to work. This is the line I added to the conftest.py:
#pytest.fixture(scope="module", autouse=True)
def spinup(testenv):
if testenv == 'local':
cmd = ['../pypyenv/bin/python', '../app.py']
p = subprocess.Popen(cmd, shell=True)
yield
p.terminate()
else:
pass
The errors I get are from the requests package that says that there is no connection/ refused.
E requests.exceptions.ConnectionError:
HTTPConnectionPool(host='localhost', port=5000): Max retries exceeded
with url: /login (Caused by
NewConnectionError(': Failed to establish a new connection:
[Errno 111] Connection refused',))
/usr/lib/python3/dist-packages/requests/adapters.py:437:
ConnectionError
This means for me that the flask server under app.py is not online. Any suggestions? I am open to more elegant alternatives
For local testing the Flask test_client is a more elegant solution. See the docs on Testing. You can create a fixture for the test_client and create test requests with that:
#pytest.fixture
def app():
app = create_app()
yield app
# teardown here
#pytest.fixture
def client(app):
return app.test_client()
And use it like this:
def test_can_login(client):
response = client.post('/login', data={username='username', password='password'})
assert response.status_code == 200
If the only problem are the manual steps, maybe consider a bash script that does your manual setup for you and after that executes pytest.
I am using the following for this purpose so that testing configuration is also preserved in the test server
#pytest.fixture(scope="session")
def app():
db_fd, db_path = tempfile.mkstemp()
app = create_app({
'TESTING': True,
'DATABASE': db_path
})
yield app
os.close(db_fd)
os.unlink(db_path)
from flask import request
def shutdown_server():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
#pytest.fixture
def server(app):
#app.route('/shutdown',methods=('POST',))
def shutdown():
shutdown_server()
return 'Shutting down server ...'
import threading
t = threading.Thread(target=app.run)
yield t.start()
import requests
requests.post('http://localhost:5000/shutdown')
References
https://flask.palletsprojects.com/en/1.1.x/tutorial/tests/
How do I terminate a flask app that's running as a service?
How to stop flask application without using ctrl-c
With a bash script (thanks #ekuusela) I now finally succeeded in what I wanted.
I added a fixture that calls the bashscript spinserver.sh in a new terminal window. This works in ubuntu, the command is different in different environments (see Execute terminal command from python in new terminal window? for other environments).
#pytest.fixture(scope="session", autouse=True)
def client(testenv):
if testenv != 'local':
pass
else:
p = subprocess.Popen(['gnome-terminal', '-x', './spinserver.sh'])
time.sleep(3)
yield
Here the very simple bashscript
#!/bin/bash
cd ..
source pypyenv/bin/activate
python app.py
The sleep command is necessary because the server takes some time to
initialize.
Don't forget to make your bash script executable (chmod
u+x spinserver.sh)
I tried to do a teardown after yield, but p.kill does not really
close the window. This is acceptable for me as it does not matter
if I have to manually close a terminal window & I can even see
flask debugging if necessary