python - 测试 django 应用程序时 github 工作流失败
问题描述
我创建了一个 django rest api,并且正在设置一个仅执行 linting 和测试的 github 操作。
我使用 pytest、pytest-django 和 pytest-cov 在本地运行测试,所有测试都通过了。Django 创建虚拟数据库并测试 api。
当我运行 github 操作时出现错误(见下文),我认为这是由于 github 环境内部没有数据库。
这是 github 操作:
name: Django CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.7, 3.8, 3.9]
services:
db:
image: postgres:12.3-alpine
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: github_actions
ports:
- 5432:5432
options: --mount type=tmpfs,destination=/var/lib/postgresql/data --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: psycopg2 prerequisites
run: sudo apt-get install libpq-dev
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Run migrations
run: python django_api-project/manage.py migrate
env:
SYSTEM_ENV: GITHUB_WORKFLOW
DJANGO_SETTINGS_MODULE: django_api.settings
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Run Tests
run: |
pytest django_api-project -s -v --durations=0 --cov=. -m "not skip_in_ci"
env:
SYSTEM_ENV: GITHUB_WORKFLOW
DJANGO_SETTINGS_MODULE: django_api.settings
以下是执行 pytest 步骤时出现的错误。
你知道这里有什么问题吗?
Run pipenv run pytest django_api-project/api -s -v --durations=0 --cov=. -m "not skip_in_ci"
============================= test session starts ==============================
platform linux -- Python 3.7.11, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- /home/runner/.local/share/virtualenvs/django-restAPI-5iRsuPs6/bin/python
cachedir: .pytest_cache
django: settings: django_api.settings (from ini)
rootdir: /home/runner/work/django-restAPI/django-restAPI, configfile: pytest.ini
plugins: flake8-1.0.7, cov-2.12.1, django-4.4.0
collecting ... collected 7 items
django_api-project/api/tests/test_api.py::test_zero_companies_should_return_empty_list Operations to perform:
Synchronize unmigrated apps: messages, rest_framework, staticfiles
Apply all migrations: admin, auth, contenttypes, sessions
Running pre-migrate handlers for application admin
Running pre-migrate handlers for application auth
Running pre-migrate handlers for application contenttypes
Running pre-migrate handlers for application sessions
Running pre-migrate handlers for application api
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
Running migrations:
Applying contenttypes.0001_initial... OK (0.006s)
Applying auth.0001_initial... OK (0.018s)
Applying admin.0001_initial... OK (0.011s)
Applying admin.0002_logentry_remove_auto_add... OK (0.013s)
Applying admin.0003_logentry_add_action_flag_choices... OK (0.012s)
Applying contenttypes.0002_remove_content_type_name... OK (0.027s)
Applying auth.0002_alter_permission_name_max_length... OK (0.033s)
Applying auth.0003_alter_user_email_max_length... OK (0.013s)
Applying auth.0004_alter_user_username_opts... OK (0.009s)
Applying auth.0005_alter_user_last_login_null... OK (0.014s)
Applying auth.0006_require_contenttypes_0002... OK (0.001s)
Applying auth.0007_alter_validators_add_error_messages... OK (0.011s)
Applying auth.0008_alter_user_username_max_length... OK (0.013s)
Applying auth.0009_alter_user_last_name_max_length... OK (0.014s)
Applying auth.0010_alter_group_name_max_length... OK (0.016s)
Applying auth.0011_update_proxy_permissions... OK (0.010s)
Applying auth.0012_alter_user_first_name_max_length... OK (0.012s)
Creating test database for alias 'default' ('file:memorydb_default?mode=memory&cache=shared')...
Applying sessions.0001_initial... OK (0.003s)
Running post-migrate handlers for application admin
Adding content type 'admin | logentry'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Running post-migrate handlers for application auth
Adding content type 'auth | permission'
Adding content type 'auth | group'
Adding content type 'auth | user'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Running post-migrate handlers for application contenttypes
Adding content type 'contenttypes | contenttype'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Running post-migrate handlers for application sessions
Adding content type 'sessions | session'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Adding permission 'Permission object (None)'
Running post-migrate handlers for application api
ERROR
django_api-project/api/tests/test_api.py::test_one_company_success ERROR
django_api-project/api/tests/test_api.py::test_empty_company ERROR
django_api-project/api/tests/test_api.py::test_company_already_exist ERROR
django_api-project/api/tests/test_api.py::test_create_new_company ERROR
django_api-project/api/tests/test_api.py::test_create_layoff_company ERROR
django_api-project/api/tests/test_api.py::test_create_company_wrong_status ERROR
==================================== ERRORS ====================================
________ ERROR at setup of test_zero_companies_should_return_empty_list ________
self = <django.db.backends.utils.CursorWrapper object at 0x7f8c808dee10>
sql = 'SELECT "api_company"."id", "api_company"."name", "api_company"."status", "api_company"."last_update", "api_company"."application_link", "api_company"."notes" FROM "api_company" ORDER BY "api_company"."id" ASC'
params = ()
ignored_wrapper_args = (False, {'connection': <django.db.backends.sqlite3.base.DatabaseWrapper object at 0x7f8c81462850>, 'cursor': <django.db.backends.utils.CursorWrapper object at 0x7f8c808dee10>})
def _execute(self, sql, params, *ignored_wrapper_args):
self.db.validate_no_broken_transaction()
with self.db.wrap_database_errors:
if params is None:
# params default might be backend specific.
return self.cursor.execute(sql)
else:
> return self.cursor.execute(sql, params)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:84:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <django.db.backends.sqlite3.base.SQLiteCursorWrapper object at 0x7f8c808e1eb0>
query = 'SELECT "api_company"."id", "api_company"."name", "api_company"."status", "api_company"."last_update", "api_company"."application_link", "api_company"."notes" FROM "api_company" ORDER BY "api_company"."id" ASC'
params = ()
def execute(self, query, params=None):
if params is None:
return Database.Cursor.execute(self, query)
query = self.convert_query(query)
> return Database.Cursor.execute(self, query, params)
E sqlite3.OperationalError: no such table: api_company
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/sqlite3/base.py:423: OperationalError
The above exception was the direct cause of the following exception:
request = <SubRequest '_django_db_marker' for <Function test_zero_companies_should_return_empty_list>>
@pytest.fixture(autouse=True)
def _django_db_marker(request) -> None:
"""Implement the django_db marker, internal to pytest-django.
This will dynamically request the ``db``, ``transactional_db`` or
``django_db_reset_sequences`` fixtures as required by the django_db marker.
"""
marker = request.node.get_closest_marker("django_db")
if marker:
transaction, reset_sequences, databases = validate_django_db(marker)
# TODO: Use pytest Store (item.store) once that's stable.
request.node._pytest_django_databases = databases
if reset_sequences:
request.getfixturevalue("django_db_reset_sequences")
elif transaction:
request.getfixturevalue("transactional_db")
else:
> request.getfixturevalue("db")
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/pytest_django/plugin.py:470:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/pytest_django/fixtures.py:120: in django_db_setup
**setup_databases_args
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/test/utils.py:183: in setup_databases
serialize=connection.settings_dict['TEST'].get('SERIALIZE', True),
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/base/creation.py:90: in create_test_db
self.connection._test_serialized_contents = self.serialize_db_to_string()
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/base/creation.py:136: in serialize_db_to_string
serializers.serialize("json", get_objects(), indent=None, stream=out)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/core/serializers/__init__.py:129: in serialize
s.serialize(queryset, **options)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/core/serializers/base.py:90: in serialize
for count, obj in enumerate(queryset, start=1):
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/base/creation.py:133: in get_objects
yield from queryset.iterator()
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/models/query.py:353: in _iterator
yield from self._iterable_class(self, chunked_fetch=use_chunked_fetch, chunk_size=chunk_size)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/models/query.py:51: in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/models/sql/compiler.py:1175: in execute_sql
cursor.execute(sql, params)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:66: in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:75: in _execute_with_wrappers
return executor(sql, params, many, context)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:84: in _execute
return self.cursor.execute(sql, params)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/utils.py:90: in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:84: in _execute
return self.cursor.execute(sql, params)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <django.db.backends.sqlite3.base.SQLiteCursorWrapper object at 0x7f8c808e1eb0>
query = 'SELECT "api_company"."id", "api_company"."name", "api_company"."status", "api_company"."last_update", "api_company"."application_link", "api_company"."notes" FROM "api_company" ORDER BY "api_company"."id" ASC'
params = ()
def execute(self, query, params=None):
if params is None:
return Database.Cursor.execute(self, query)
query = self.convert_query(query)
> return Database.Cursor.execute(self, query, params)
E django.db.utils.OperationalError: no such table: api_company
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/sqlite3/base.py:423: OperationalError
__________________ ERROR at setup of test_one_company_success __________________
self = <django.db.backends.utils.CursorWrapper object at 0x7f8c808dee10>
sql = 'SELECT "api_company"."id", "api_company"."name", "api_company"."status", "api_company"."last_update", "api_company"."application_link", "api_company"."notes" FROM "api_company" ORDER BY "api_company"."id" ASC'
params = ()
ignored_wrapper_args = (False, {'connection': <django.db.backends.sqlite3.base.DatabaseWrapper object at 0x7f8c81462850>, 'cursor': <django.db.backends.utils.CursorWrapper object at 0x7f8c808dee10>})
def _execute(self, sql, params, *ignored_wrapper_args):
self.db.validate_no_broken_transaction()
with self.db.wrap_database_errors:
if params is None:
# params default might be backend specific.
return self.cursor.execute(sql)
else:
> return self.cursor.execute(sql, params)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:84:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <django.db.backends.sqlite3.base.SQLiteCursorWrapper object at 0x7f8c808e1eb0>
query = 'SELECT "api_company"."id", "api_company"."name", "api_company"."status", "api_company"."last_update", "api_company"."application_link", "api_company"."notes" FROM "api_company" ORDER BY "api_company"."id" ASC'
params = ()
def execute(self, query, params=None):
if params is None:
return Database.Cursor.execute(self, query)
query = self.convert_query(query)
> return Database.Cursor.execute(self, query, params)
E sqlite3.OperationalError: no such table: api_company
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/sqlite3/base.py:423: OperationalError
The above exception was the direct cause of the following exception:
request = <SubRequest '_django_db_marker' for <Function test_one_company_success>>
@pytest.fixture(autouse=True)
def _django_db_marker(request) -> None:
"""Implement the django_db marker, internal to pytest-django.
This will dynamically request the ``db``, ``transactional_db`` or
``django_db_reset_sequences`` fixtures as required by the django_db marker.
"""
marker = request.node.get_closest_marker("django_db")
if marker:
transaction, reset_sequences, databases = validate_django_db(marker)
# TODO: Use pytest Store (item.store) once that's stable.
request.node._pytest_django_databases = databases
if reset_sequences:
request.getfixturevalue("django_db_reset_sequences")
elif transaction:
request.getfixturevalue("transactional_db")
else:
> request.getfixturevalue("db")
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/pytest_django/plugin.py:470:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/pytest_django/fixtures.py:120: in django_db_setup
**setup_databases_args
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/test/utils.py:183: in setup_databases
serialize=connection.settings_dict['TEST'].get('SERIALIZE', True),
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/base/creation.py:90: in create_test_db
self.connection._test_serialized_contents = self.serialize_db_to_string()
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/base/creation.py:136: in serialize_db_to_string
serializers.serialize("json", get_objects(), indent=None, stream=out)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/core/serializers/__init__.py:129: in serialize
s.serialize(queryset, **options)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/core/serializers/base.py:90: in serialize
for count, obj in enumerate(queryset, start=1):
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/base/creation.py:133: in get_objects
yield from queryset.iterator()
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/models/query.py:353: in _iterator
yield from self._iterable_class(self, chunked_fetch=use_chunked_fetch, chunk_size=chunk_size)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/models/query.py:51: in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/models/sql/compiler.py:1175: in execute_sql
cursor.execute(sql, params)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:66: in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:75: in _execute_with_wrappers
return executor(sql, params, many, context)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:84: in _execute
return self.cursor.execute(sql, params)
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/utils.py:90: in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
../../../.local/share/virtualenvs/django-restAPI-5iRsuPs6/lib/python3.7/site-packages/django/db/backends/utils.py:84: in _execute
return self.cursor.execute(sql, params)
解决方案
推荐阅读
- c++ - extern global 似乎会导致链接器错误
- javascript - 如何通过添加空格使所有文件名的长度相同?
- javascript - 如何将 snapshot.val() 中的数据提升到组件的状态?
- python - (Python 图形工具)使用图形工具查找特定长度的路径?
- php - 如何在php中将n-dash字符转换为csv
- python - 如何使用networkx图根据中间节点的属性值找到2个节点之间的路径?
- c# - 有没有办法通过让用户选择输入数字退出来退出这个 do while 循环?
- vba - 项目符号列表或编号列表未突出显示 vba
- java - 当实际页面较大时如何在虚拟页面周围打印边框
- java - 来自可选依赖项的 Aspectj 切入点定位注解