pytest doesn't execute project/__init__.py - python

I have the structure of project like:
chats
__init__.py
messenger.py
tests
test_acs.py
__init__.py
here is the code in test_acs.py:
from chats import messenger
import asyncio
import pytest
import os
def test_get_last_message():
os.environ["API_ID"] = 'API_ID'
os.environ["API_HASH"] = 'API_HASH'
assert asyncio.new_event_loop().run_until_complete(messenger.get_last_message('PARAM')) == '1'
here is the code in __init__.py:
from os import environ
API_ID = environ.get('API_ID')
API_HASH = environ.get('API_HASH')
But when I try to use API_ID / API_HASH in messenger.get_last_message() - python doesn't see them.
I checked and it turns out that pytest doesn't run chats/init.py at all, which is very strange. Maybe there are ideas? I start tests with python -m pytest from root directory. Thank you

Related

force subprocss to return a value before importing a module

Objective : To Create UnitTestCases for main.py
How can we run subprocess.run as unittest case
File : main.py
import os
_ENV = os.environ['server']
BASE_PATH = '/home/test'
SERVER_URL = {
'DEV':{'ENV_URL':'https://dev.net'},
'UAT':{'ENV_URL':'https://uat.net'},
'PROD':{'ENV_URL':'https://prod.net'}
}[_ENV]
if _CYBERARK=='DYNAMIC' and _ENV.upper() in ('DEV','UAT','PROD') :
TOKEN = json.load(open(BASE_PATH + "secrets/cyberark_env.json"))
APPID = CONFIGURE_TOKEN.get('desc').get('appID')
## --> error on this because its running .sh files
VALUE=subprocess.run(["sh",BASE_PATH + "bin/cyberark.sh",APPID],capture_output=True,text=True).stdout.strip()
In my test_main.py
I am trying to import main.py to my test.py without any issues, but i find it challenging on how we to manually make VALUE variable return as 'ABCD'
Similar to below scripts
Testing : test_main.py
import unittest, sys
from unittest import mock
os.environ['server']='DEV'
# Similar to os.environ , i want to create temporarily VALUE before import main is called.
sys.path.insert(1, 'C:/home/src')
import main.py as conf
class test_tbrp_case(unittest.TestCase):
def test_port(self):
#function yet to be created
pass
if __name__=='__main__':
unittest.main()
Is this achieveable or i need to relogic my whole function

Import path in pytest

I have Python Flask project with following structure of my project (I removed uneccesary things):
server
src
service
__init__.py
User.py
tests
pytest.ini
service
test_user.py
Where pytest.ini contains:
[pytest]
python_paths = ../src
And test_user.py:
from service.User import UserService
def test_empty_db():
service = UserService()
users = service.get_all() # Get all users from DB.
assert len(users) = 0 # There should be users.
Now, I would like to run this test. When I run pytest or pytest server from root of project, everything is ok. However, when I want to run the specified file pytest server/tests/service/test_user.py error appears:
from services.User import UserService
E ModuleNotFoundError: No module named 'service'
Is there any way to fix it?
You can try to make your imports more absolute inside your test_user.py like: from server.src.service.User import …
Or you can also try adding a __init__.py to your tests directory.
Your error message is showing services.User while you code is showing service.User, could it be a typo?

pytest return ModuleNotFoundError when module imported in test file import another module within the same directory of the imported module

I am sorry if the title takes some time to understand. So here is the folder structure:
falcon_tut/
falcon_tut/
app.py
images.py
__init__.py
tests/
test_app.py
__init__.py
And some codes
####################
# app.py
####################
from images import Resource
images = Resource()
api = application = falcon.API()
api.add_route('/images', images)
# ... few more codes
####################
# test_app.py
####################
import falcon
from falcon import testing
import ujson
import pytest
from falcon_tut.app import api
#pytest.fixture
def client():
return testing.TestClient(api)
def test_list_images(client):
doc = {
'images': [
{
'href': '/images/1eaf6ef1-7f2d-4ecc-a8d5-6e8adba7cc0e.png'
}
]
}
response = client.simulate_get('/images')
result_doc = ujson.loads(response.content)
assert result_doc == doc
assert response.status == falcon.HTTP_OK
It works fine when running with python falcon_tut/app.py and curl it with response of 200 and payload of the images
Until running pytest tests/ from the project root it output this:
ImportError while importing test module ../falcon_tut/tests/test_app.py
Hint: make sure your test modules/packages have valid Python names.
Traceback:
tests/test_app.py:6: in <module>
from falcon_tut.app import api
E ModuleNotFoundError: No module named 'falcon_tut'
I tried creating __init__.py at the project root but it still output the same error above
Python version 3.7.0, with falcon 1.4.1, cpython 0.28.5, pytest 3.7.3, and instead of using gunicorn, I am using bjoern 2.2.2
I am trying out the python falcon framework and encounter the error at the testing part.
==========UPDATE===========
The reason why pytest could not found the module is because sys.path does not have ../falcon_tut/falcon_tut exists.
When I ran pytest and edit those 2 files and printing out sys.path, it only has [../falcon_tut/tests, ../falcon_tut, ..]. The workaround to this is to append the path to the package to sys.path. So here is the edited app.py
#############
# app.py
#############
import sys
# this line is just example, please rewrite this properly if you wants to use this workaround
# sys_path[1] only applied to my situation, again this is just example to know that it works
# the idea is to make sure the path to your module exists in sys.path
# in this case, I appended ../falcon_tut/falcon_tut to sys.path
# so that now ../falcon_tut/falcon_tut/images.py can be found by pytest
sys.path.insert(0, '{}/falcon_tut'.format(sys_path[1]))
# body codes...

Using PyTest with hug and base_url

I have a an api that is setup with
import hug
API = hug.API(__name__).http.base_url='/api'
#hug.get('/hello-world', versions=1)
def hello_world(response):
return hug.HTTP_200
and I'm trying to test it with PyTest.
I'm trying to test the route with
import pytest
import hug
from myapi import api
...
def test_hello_world_route(self):
result = hug.test.get(myapp, 'v1/hello-world')
assert result.status == hug.HTTP_200
How can I test hug routes that have http.base_url configured?
I get a 404 errors regardless of the route path. I've tried
/api/v1/hello-world
api/v1/hello-world
v1/hello-world
/v1/hello-world
If I remove the hug.API().http.base_url setting then v1/hello-world works fine but my requirement is to have a base_url setup.
I've reviewed the documentation on the official hug github repo and various online sources such as ProgramTalk but I haven't had much success.
any recommendations?
You should send your module (myapp) as the first argument to hug.test.get().
Then you can use the full path /api/v1/hello-world as the second argument.
Here's a minimal working example:
# myapp.py
import hug
api = hug.API(__name__).http.base_url='/api'
#hug.get('/hello-world', versions=1)
def hello_world(response):
return hug.HTTP_200
.
# tests.py
import hug
import myapp
def test_hello_world_route():
result = hug.test.get(myapp, '/api/v1/hello-world')
assert result.status == hug.HTTP_200
.
# run in shell
pytest tests.py

More elegant solution for python imports across app/tests?

I'm trying to keep my code reasonably organized by putting tests in a separate directory from my app. However, imports work either for the app or for the tests, but not both. Here's a contrived example that illustrates my current problem:
myapp/
app/
main.py
settings.py
moods.py
test/
test_moods.py
Contents of files as follows:
main.py
import settings
from moods import Moods
words = Moods(settings.EXAMPLE)
print(words.excited())
settings.py
EXAMPLE = "Wow$ Python$"
DELIM = "$"
moods.py
import settings
class Moods:
def __init__(self, text):
self.text = text
def excited(self):
return self.text.replace(settings.DELIM, "!!!")
test_moods.py
import sys, os, unittest
sys.path.insert(0, os.path.abspath('..'))
from app.moods import Moods
class TestMood(unittest.TestCase):
def setUp(self):
self.words = Moods("Broken imports$ So sad$")
def test_mood(self):
self.assertEqual(self.words.excited(), "Broken imports!!! So sad!!!")
with self.assertRaises(AttributeError):
self.words.angry()
if __name__ == "__main__":
unittest.main()
In the current state, from myapp/ I can run the following successfully:
>> python3 app/main.py
Wow!!! Python!!!
But when I try to run tests, the import fails in moods.py:
>> python3 -m unittest discover test/
ImportError: Failed to import test module: test_moods
[ stack trace here pointing to first line of moods.py ]
ImportError: No module named 'settings'
If I modify line 1 of moods.py to read from app import settings, the test will pass, but normal execution of the app fails because it sees no module app.
The only solutions I can think of are
Putting the tests in the same directory as the code (which I was trying to avoid)
Adding the sys.path.insert(0, os.path.abspath('..')) to each file in my app to make the imports work the same as the test ones do (which seems messy)
Is there are more elegant way to solve this import problem?
You should have both app and test directory in PYTHONPATH.
One way is to replace this:
sys.path.insert(0, os.path.abspath('..'))
from app.moods import Moods
with this:
sys.path.insert(0, os.path.abspath('../app'))
from moods import Moods
Or you can set the PYTHONPATH environament variable before running the tests.
Why? Because when you run main.py, then app is in the path, not app/.., so you want to have the same when running tests.

Categories