pytest-django
pytest-django copied to clipboard
How to test stripe webhook using pytest-django
I have a docker-compose based development environment with
services:
django:
postgres:
stripe:
command: listen --forward-to http://django:8000/stripe/webhook
When the user uses stripe to make a payment, an event is forwarded by stripe to a webhook http://django:800/stripe/webhook, handled by the django instance.
When I use pytest to test the service, the following happens (as far as I understand):
djangois still running with access to the regular database- A
live_serverwith--ds=config.settings.testis created with access to the test database - When a payment is made during testing,
stripestill forwards the request todjango, which accesses the regular database, NOT the test database that is hooked tolive_server, and the test payment would fail.
To fix this problem, we may
- Fix
stripe: Somehow configurestripeto--forward-to live_server.url/stripe/webhoo. This is what is supposed to happen but requires a differentstripe cliinstance to be created afterlive_server.urlis determined. - Keep
--forward-toto the regulardjangoinstance, butdjango(NOTlive_server) will access the test database to complete the test. This may be easier but I am not sure how to configuredjangoto access the test database.
Does anyone have any suggestions on how to do this properly?
Edit: A third option maybe running the tests on django directly without firing up a live_server, and using the normal database. The trouble is then how to direct pytest-django to NOT use the test database.
It is quite a bit of exploratory work but here is how option two can be implemented:
- In
settings.test, addnon_test_dbas a placeholder for the original "normal" database. This should probably be a separate setting file to avoid demanding other tests to listnon_test_dbindjango_db.
DATABASES['non_test_db'] = copy.deepcopy(DATABASES['default'])
- Define a
DATABASE_ROUTERto usenon_test_db,
class NO_TEST_DB_ROUTER(object):
def db_for_read(self, model, **hints):
return 'non_test_db'
def db_for_write(self, model, **hints):
return 'non_test_db'
def allow_relation(self, obj1, obj2, **hints):
return True
def allow_migrate(self, db, app_label, model_name=None, **hints):
return True
- define a fixture to switch the database operation on the non-test-database
@pytest.fixture
def non_test_db(settings):
oldname = settings.DATABASES['non_test_db']['NAME']
settings.DATABASES['non_test_db']['NAME'] = oldname.split('_')[1]
settings.DATABASE_ROUTERS = ['bioworkflows.tests.utils.NO_TEST_DB_ROUTER']
yield
settings.DATABASES['non_test_db']['NAME'] = oldname
settings.DATABASE_ROUTERS = []
- Finally, for the test that need to access the non-test database,
@override_settings(ALLOWED_HOSTS=['*'])
@pytest.mark.django_db(databases=['default', 'non_test_db'])
def test_post_bounty(non_test_db):
pass
What is happening here is that when the test is started, the non_test_db fixture will modify settings.DATABASES and point non_test_db to the original database, and add a DATABASE_ROUTERS to force all database options to happen on the non-test database. This fixture needs to be placed before any other database-operating fixtures.
This will allow the tests to operate on the non-test database with data accessible by the webhook