Reputation: 2407
While using py.test, I have some tests that run fine with SQLite but hang silently when I switch to Postgresql. How would I go about debugging something like that? Is there a "verbose" mode I can run my tests in, or set a breakpoint ? More generally, what is the standard plan of attack when pytest stalls silently? I've tried using the pytest-timeout, and ran the test with $ py.test --timeout=300, but the tests still hang with no activity on the screen whatsoever
Upvotes: 52
Views: 41898
Reputation: 4368
To answer the question "How would I go about debugging something like that?"
Run with pytest --trace
to get trace of python calls.
One option (useful for any stuck unix binary) is to attach to process using strace -p <PID>
. See what system call it might be stuck on or loop of system calls. e.g. stuck calling gettimeofday
For more verbose py.test output install pytest-sugar. pip install pytest-sugar
And run test with pytest --verbose . . .
https://pypi.python.org/pypi/pytest-sugar
Upvotes: 16
Reputation: 51
I believe this problem could be caused by many reasons.
In my case:
I was running a test that depends on a fixture. The fixture is doing some SQLAlchemy operation with a Postgres database.
The real fixture is quite complicated and I will just give a simple example to point out the problem.
Here is my testcase:
@pytest.fixture
def my_fixture():
message = "Hello World"
success = True
return message, success
def test_something(my_fixture):
print("Good day")
assert 1 == 1
My testcase hang and didn't show any error message. "Good day" is not printed to the log. Apparently the problem is in the fixture.
I tried changing the fixture to use yield
instead of return
, and it doesn't hang anymore.
@pytest.fixture
def my_fixture():
message = "Hello World"
success = True
yield message, success
I don't know why but it does fix the problem.
Upvotes: 0
Reputation: 1420
For me the solution to get rid of a hanging test was to use the pytest plugin pytest-xdist (and to run the tests in parallel). I am unsure why that solved it. The reason might be that the plugin runs the tests in (multiple) threads.
Upvotes: 0
Reputation: 1390
In my case diff worked very slow on comparing 4 MB data when assert failed.
with open(path, 'rb') as f:
assert f.read() == data
Fixed by:
with open(path, 'rb') as f:
eq = f.read() == data
assert eq
Upvotes: -1
Reputation: 2411
I just ran into this problem for quite some time (though I wasn't using SQLite). The test suite ran fine locally, but failed in CircleCI (Docker).
My problem was ultimately that:
__del__
normally would end the threads__del__
as it should haveI figured I'd add how I figured this out. Other answers suggest these:
pytest-timeout
didn't help, the test hung after completion
pytest --timeout 5
pytest==6.2.2, pytest-timeout==1.4.2
pytest -m trace --trace
or pytest --verbose
yielded no useful information eitherI ended up having to comment literally everything out, including:
conftest.py
code and test code__del__
Upvotes: 2
Reputation: 531
I ran into the same SQLite/Postgres problem with Flask and SQLAlchemy, similar to Gordon Fierce. However, my solution was different. Postgres is strict about table locks and connections, so explicitly closing the session connection on teardown solved the problem for me.
My working code:
@pytest.yield_fixture(scope='function')
def db(app):
# app is an instance of a flask app, _db a SQLAlchemy DB
_db.app = app
with app.app_context():
_db.create_all()
yield _db
# Explicitly close DB connection
_db.session.close()
_db.drop_all()
Reference: SQLAlchemy
Upvotes: 31
Reputation: 21877
In my case the Flask application did not check if __name__ == '__main__':
so it executed app.start()
when that was not my intention.
You can read many more details here.
Upvotes: 1
Reputation: 319
I had a similar problem with pytest and Postgresql while testing a Flask app that used SQLAlchemy. It seems pytest has a hard time running a teardown using its request.addfinalizer method with Postgresql.
Previously I had:
@pytest.fixture
def db(app, request):
def teardown():
_db.drop_all()
_db.app = app
_db.create_all()
request.addfinalizer(teardown)
return _db
( _db is an instance of SQLAlchemy I import from extensions.py ) But if I drop the database every time the database fixture is called:
@pytest.fixture
def db(app, request):
_db.app = app
_db.drop_all()
_db.create_all()
return _db
Then pytest won't hang after your first test.
Upvotes: 10
Reputation: 2407
Not knowing what is breaking in the code, the best way is to isolate the test that is failing and set a breakpoint in it to have a look. Note: I use pudb instead of pdb, because it's really the best way to debug python if you are not using an IDE.
For example, you can the following in your test file:
import pudb
...
def test_create_product(session):
pudb.set_trace()
# Create the Product instance
# Create a Price instance
# Add the Product instance to the session.
...
Then run it with
py.test -s --capture=no test_my_stuff.py
Now you'll be able to see exactly where the script locks up, and examine the stack and the database at this particular moment of execution. Otherwise it's like looking for a needle in a haystack.
Upvotes: 6