Gitlab CI/CD 管道在迁移之前运行 Django 单元测试
Gitlab CI/CD Pipeline Runs Django Unit Tests Before Migrations
问题
我正在尝试在 Gitlab 的 CI/CD 中设置一个测试阶段。在本地,运行 单元测试正常进行并符合预期。但是,在 Gitlab 的 CI/CD 中,当 运行ning 脚本 coverage run manage.py test -v 2 && coverage report
时,单元测试正在执行 before迁移在测试数据库中完成,这是意想不到的,并且总是会失败。测试数据库上的迁移需要 运行 在单元测试执行之前。
知道为什么会发生这种行为吗?
当 运行 宁 python manage.py test
这些是默认发生的步骤:
创建测试数据库。
数据库迁移。
运行 系统检查。
运行正在测试。
报告测试次数和成功/失败。
正在删除测试数据库。
在下面的 本地测试 运行 输出 中,您可以看到这些确切的步骤,按顺序发生。问题是,在 Gitlab 的 CI/CD 管道中,第 2 步和第 4 步由于某种神秘原因被切换了。
我已经尝试过的东西
- 删除覆盖,只执行
python manage.py test
结果:同样的错误
- 删除用户测试,其中 Gitlab 表示测试失败:结果:同样的错误
- 删除除一个单元测试以外的所有单元测试以尝试隔离:结果:同样的错误
- 在 Gitlab 的容器中添加并激活虚拟环境:结果:同样的错误
- 尝试 SQLite3:结果:迁移失败,因为 SQLite3 不支持项目中必需的必要数组字段
Gitlab CI/CD 输出
我的实际产量要大得多。但这里是相关部分:
$ echo $TEST_SECRETS | base64 -d > config/settings/local.py
$ echo RUNNING UNIT TESTS
RUNNING UNIT TESTS
$ coverage run manage.py test -v 2 && coverage report
Creating test database for alias 'default' ('test_mia')...
test_dataconnector_category_creation_delete (apps.core.tests.test_models.DataConnectorCategoryTestCase)
Verify data connector category creation ... ok
test_compare_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compare object from self.airbytesetting to ensure data is in proper format. ... ok
test_fieldconstraints_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Test updating values in self.airbytesetting and saving that to the test database. ... ok
test_compare_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compare object from self.airbytesource to ensure data is in proper format. ... ok
test_delete_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test Deleting self.airbytesource object from database ... ok
test_fieldconstraints_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test updating values in self.airbytesource and saving that to the test database. ... ok
test_compare_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compare object from self.airbytestream to ensure data is in proper format. ... ok
test_delete_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test Deleting self.airbytestream object from database ... ok
test_fieldconstraints_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test updating values in self.airbytestream and saving that to the test database. ... ok
test_compare_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compare object from self.airbytesynccatalog to ensure data is in proper format. ... ok
test_delete_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test Deleting self.airbytesynccatalog object from database ... ok
test_fieldconstraints_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test updating values in self.airbytesynccatalog and saving that to the test database. ... ok
test_compare_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compare object from self.tableausetting to ensure data is in proper format. ... ok
test_createrandom_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Creating a New (Second) TableauSetting Model Object with Random Values. ... ok
test_delete_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Deleting self.tableausetting object from database ... ok
test_fieldconstraints_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test updating values in self.tableausetting and saving that to the test database. ... ok
test_get_namespace_custom_format (apps.services.tests.test_scripts_airbyte.ServicesTestCase)
TO-DO: this method should live in AirByte class ... ok
test_retrieve_me_user (apps.user.tests.test_views.UserViewTest) ... ok
test_retrieve_user (apps.user.tests.test_views.UserViewTest) ... ok
apps.user.tests.test_models (unittest.loader._FailedTest) ... ERROR
======================================================================
ERROR: apps.user.tests.test_models (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: apps.user.tests.test_models
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "user_user" does not exist
LINE 1: INSERT INTO "user_user" ("password", "last_login", "is_super...
^
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/unittest/loader.py", line 436, in _find_test_path
module = self._get_module_from_name(name)
File "/usr/local/lib/python3.8/unittest/loader.py", line 377, in _get_module_from_name
__import__(name)
File "/builds/americommerce/mia/mia-ms-main/apps/user/tests/test_models.py", line 3, in <module>
from apps.user.tests.factories import UserFactory, CompanyFactory, SignUpTokenFactory
File "/builds/americommerce/mia/mia-ms-main/apps/user/tests/factories.py", line 23, in <module>
class SignUpTokenFactory(factory.django.DjangoModelFactory):
File "/builds/americommerce/mia/mia-ms-main/apps/user/tests/factories.py", line 28, in SignUpTokenFactory
user = UserFactory()
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 40, in __call__
return cls.create(**kwargs)
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 528, in create
return cls._generate(enums.CREATE_STRATEGY, kwargs)
File "/usr/local/lib/python3.8/site-packages/factory/django.py", line 117, in _generate
return super()._generate(strategy, params)
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 465, in _generate
return step.build()
File "/usr/local/lib/python3.8/site-packages/factory/builder.py", line 262, in build
instance = self.factory_meta.instantiate(
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 317, in instantiate
return self.factory._create(model, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/factory/django.py", line 166, in _create
return manager.create(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 447, in create
obj.save(force_insert=True, using=self.db)
File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/base_user.py", line 67, in save
super().save(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 753, in save
self.save_base(using=using, force_insert=force_insert,
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 790, in save_base
updated = self._save_table(
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 895, in _save_table
results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 933, in _do_insert
return manager._insert(
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 1254, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1397, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python3.8/site-packages/sentry_sdk/integrations/django/__init__.py", line 508, in execute
return real_execute(self, sql, params)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 66, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "user_user" does not exist
LINE 1: INSERT INTO "user_user" ("password", "last_login", "is_super...
^
----------------------------------------------------------------------
Ran 25 tests in 0.648s
FAILED (errors=1)
Destroying test database for alias 'default' ('test_mia')...
Operations to perform:
Synchronize unmigrated apps: corsheaders, debug_toolbar, delete_migrations, django_filters, generic_relations, messages, mptt, rest_framework, rest_framework_jwt, rest_framework_swagger, staticfiles
Apply all migrations: admin, auth, contenttypes, core, dashboard, reports, services, sessions, store, user
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
Running migrations:
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying user.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying store.0001_initial... OK
Applying dashboard.0001_initial... OK
Applying core.0001_initial... OK
Applying reports.0001_initial... OK
Applying reports.0002_emailreport_store... OK
Applying reports.0003_initial... OK
Applying reports.0004_remove_emailreport_segments... OK
Applying core.0002_dataconnectorcategory... OK
Applying core.0003_auto_20220331_1610... OK
Applying core.0004_delete_segment... OK
Applying dashboard.0002_auto_20220331_1804... OK
Applying dashboard.0003_flag_tableauview_widget_widgetsection... OK
Applying reports.0005_emailreport_segments... OK
Applying services.0001_initial... OK
Applying services.0002_auto_20220325_0426... OK
Applying services.0003_auto_20220331_1610... OK
Applying sessions.0001_initial... OK
Applying store.0002_initial... OK
Applying store.0003_storefrontdataconnector... OK
Applying user.0002_auto_20220325_0426... OK
Applying user.0003_auto_20220331_1610... OK
Applying user.0004_auto_20220331_1804... OK
Applying user.0005_user_flags... OK
System check identified no issues (0 silenced).
Cleaning up project directory and file based variables
00:01
ERROR: Job failed: exit code 1
本地测试运行输出
Creating test database for alias 'default' ('test_mia')...
Operations to perform:
Synchronize unmigrated apps: corsheaders, debug_toolbar, delete_migrations, django_filters, generic_relations, messages, mptt, rest_framework, rest_framework_jwt, rest_framework_swagger, staticfiles
Apply all migrations: admin, auth, contenttypes, core, dashboard, reports, services, sessions, store, user
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
Running migrations:
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying user.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying store.0001_initial... OK
Applying dashboard.0001_initial... OK
Applying core.0001_initial... OK
Applying reports.0001_initial... OK
Applying reports.0002_emailreport_store... OK
Applying reports.0003_initial... OK
Applying reports.0004_remove_emailreport_segments... OK
Applying core.0002_dataconnectorcategory... OK
Applying core.0003_auto_20220331_1610... OK
Applying core.0004_delete_segment... OK
Applying dashboard.0002_auto_20220331_1804... OK
Applying dashboard.0003_flag_tableauview_widget_widgetsection... OK
Applying reports.0005_emailreport_segments... OK
Applying services.0001_initial... OK
Applying services.0002_auto_20220325_0426... OK
Applying services.0003_auto_20220331_1610... OK
Applying sessions.0001_initial... OK
Applying store.0002_initial... OK
Applying store.0003_storefrontdataconnector... OK
Applying user.0002_auto_20220325_0426... OK
Applying user.0003_auto_20220331_1610... OK
Applying user.0004_auto_20220331_1804... OK
Applying user.0005_user_flags... OK
System check identified no issues (0 silenced).
test_dataconnector_category_creation_delete (apps.core.tests.test_models.DataConnectorCategoryTestCase)
Verify data connector category creation ... ok
test_compare_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compare object from self.airbytesetting to ensure data is in proper format. ... ok
test_fieldconstraints_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Test updating values in self.airbytesetting and saving that to the test database. ... ok
test_compare_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compare object from self.airbytesource to ensure data is in proper format. ... ok
test_delete_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test Deleting self.airbytesource object from database ... ok
test_fieldconstraints_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test updating values in self.airbytesource and saving that to the test database. ... ok
test_compare_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compare object from self.airbytestream to ensure data is in proper format. ... ok
test_delete_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test Deleting self.airbytestream object from database ... ok
test_fieldconstraints_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test updating values in self.airbytestream and saving that to the test database. ... ok
test_compare_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compare object from self.airbytesynccatalog to ensure data is in proper format. ... ok
test_delete_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test Deleting self.airbytesynccatalog object from database ... ok
test_fieldconstraints_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test updating values in self.airbytesynccatalog and saving that to the test database. ... ok
test_compare_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compare object from self.tableausetting to ensure data is in proper format. ... ok
test_createrandom_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Creating a New (Second) TableauSetting Model Object with Random Values. ... ok
test_delete_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Deleting self.tableausetting object from database ... ok
test_fieldconstraints_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test updating values in self.tableausetting and saving that to the test database. ... ok
test_get_namespace_custom_format (apps.services.tests.test_scripts_airbyte.ServicesTestCase)
TO-DO: this method should live in AirByte class ... ok
test_company_creation (apps.user.tests.test_models.UserTestCase)
Verify Company creation ... ok
test_signup_token_creation (apps.user.tests.test_models.UserTestCase)
Verify token creation ... ok
test_user_creation (apps.user.tests.test_models.UserTestCase)
Verify User creation ... ok
test_user_creation_with_company (apps.user.tests.test_models.UserTestCase)
Verify User can be assigned company ... ok
test_user_creation_with_signup_token (apps.user.tests.test_models.UserTestCase)
Verify User can be assigned token ... ok
test_retrieve_me_user (apps.user.tests.test_views.UserViewTest) ... ok
test_retrieve_user (apps.user.tests.test_views.UserViewTest) ... ok
----------------------------------------------------------------------
Ran 29 tests in 0.521s
OK
Destroying test database for alias 'default' ('test_mia')...
Name Stmts Miss Cover
---------------------------------------------------------------------
apps/core/admin.py 5 0 100%
apps/core/exceptions.py 22 3 86%
apps/core/mixins.py 10 3 70%
apps/core/models.py 8 1 88%
apps/core/serializers.py 18 0 100%
apps/core/urls.py 5 0 100%
apps/core/utils.py 69 33 52%
apps/core/views.py 42 26 38%
apps/dashboard/admin.py 15 0 100%
apps/dashboard/models.py 34 7 79%
apps/dashboard/urls.py 6 0 100%
apps/dashboard/views.py 27 16 41%
apps/delete_migrations/admin.py 1 0 100%
apps/delete_migrations/models.py 1 0 100%
apps/reports/admin.py 14 0 100%
apps/reports/mixins.py 16 9 44%
apps/reports/models/alert.py 47 3 94%
apps/reports/models/email_report.py 31 1 97%
apps/reports/serializers/alert.py 49 14 71%
apps/reports/serializers/email_report.py 49 22 55%
apps/reports/tasks.py 71 43 39%
apps/reports/urls.py 9 0 100%
apps/reports/utils.py 12 9 25%
apps/reports/views/alerts.py 40 23 42%
apps/reports/views/reports.py 55 26 53%
apps/services/admin.py 23 6 74%
apps/services/models/airbyte.py 37 0 100%
apps/services/models/tableau.py 9 0 100%
apps/services/scripts/airbyte.py 157 126 20%
apps/services/scripts/tableau.py 69 50 28%
apps/services/urls.py 3 0 100%
apps/services/views.py 15 8 47%
apps/store/admin.py 41 0 100%
apps/store/mixins.py 12 7 42%
apps/store/models/amazon_ads.py 18 2 89%
apps/store/models/amazon_seller_partner.py 21 2 90%
apps/store/models/data_connector_base.py 28 5 82%
apps/store/models/data_connector_settings.py 18 3 83%
apps/store/models/facebook.py 17 2 88%
apps/store/models/google_ads.py 20 2 90%
apps/store/models/google_analytics.py 18 2 89%
apps/store/models/google_search_console.py 18 2 89%
apps/store/models/hubspot.py 14 2 86%
apps/store/models/klaviyo.py 12 1 92%
apps/store/models/mailchimp.py 14 2 86%
apps/store/models/shopify.py 17 2 88%
apps/store/models/store.py 13 3 77%
apps/store/models/storefront.py 19 8 58%
apps/store/serializers/amazon_ads.py 22 11 50%
apps/store/serializers/amazon_seller_partner.py 26 14 46%
apps/store/serializers/base.py 8 0 100%
apps/store/serializers/credentials.py 3 0 100%
apps/store/serializers/facebook.py 15 7 53%
apps/store/serializers/google_ads.py 23 12 48%
apps/store/serializers/google_analytics.py 22 11 50%
apps/store/serializers/google_search_console.py 22 11 50%
apps/store/serializers/hubspot.py 6 0 100%
apps/store/serializers/klaviyo.py 6 0 100%
apps/store/serializers/list_data_connectors.py 24 0 100%
apps/store/serializers/mailchimp.py 6 0 100%
apps/store/serializers/shopify.py 21 10 52%
apps/store/serializers/store.py 30 3 90%
apps/store/serializers/storefront.py 6 0 100%
apps/store/tasks.py 104 80 23%
apps/store/urls.py 26 0 100%
apps/store/utils.py 89 66 26%
apps/store/views/check_data_connector_store.py 21 13 38%
apps/store/views/credentials.py 13 3 77%
apps/store/views/delete_data_connector.py 19 10 47%
apps/store/views/detail_data_connectors.py 42 0 100%
apps/store/views/list_data_connectors.py 50 32 36%
apps/store/views/reset_data_connector.py 18 9 50%
apps/store/views/store.py 15 8 47%
apps/store/views/sync_data_connector.py 18 9 50%
apps/user/admin.py 29 7 76%
apps/user/apps.py 5 0 100%
apps/user/forms.py 14 1 93%
apps/user/models.py 72 13 82%
apps/user/serializers.py 88 31 65%
apps/user/signals.py 11 4 64%
apps/user/tasks.py 15 6 60%
apps/user/urls.py 7 0 100%
apps/user/utils.py 4 0 100%
apps/user/validators.py 7 2 71%
apps/user/views.py 61 26 57%
manage.py 13 6 54%
---------------------------------------------------------------------
TOTAL 2250 879 61%
.gitlab-ci.yml 文件
我的实际文件要大得多。但这里是相关部分:
services:
- docker:20.10.7-dind
- postgres:latest
stages:
- test
variables:
POSTGRES_DB: test_mia
POSTGRES_USER: mia_dev
POSTGRES_PASSWORD: test123
build_test_db:
image: postgres
script:
- export PGPASSWORD=$POSTGRES_PASSWORD
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT 'OK' AS status;"
test:
image: python:3.8-slim-buster
stage: test
before_script:
- |
apt-get update && apt-get install -y --no-install-recommends \
gcc \
musl-dev \
python3-dev \
libpq-dev \
libgnutls28-dev \
git \
&& rm -rf /var/lib/apt/lists/*
- python -m pip install --upgrade pip
- pip install uwsgi
- pip install -r requirements.txt
- echo $TEST_SECRETS | base64 -d > config/settings/local.py
script:
- echo RUNNING UNIT TESTS
- coverage run manage.py test -v 2 && coverage report
needs:
- ["build_test_db"]
environment: test
# only:
# - develop
在 gitlab-ci.yml
的脚本部分的 coverage run manage.py test ...
之前添加 python manage.py migrate
行。
问题
我正在尝试在 Gitlab 的 CI/CD 中设置一个测试阶段。在本地,运行 单元测试正常进行并符合预期。但是,在 Gitlab 的 CI/CD 中,当 运行ning 脚本 coverage run manage.py test -v 2 && coverage report
时,单元测试正在执行 before迁移在测试数据库中完成,这是意想不到的,并且总是会失败。测试数据库上的迁移需要 运行 在单元测试执行之前。
知道为什么会发生这种行为吗?
当 运行 宁 python manage.py test
这些是默认发生的步骤:
创建测试数据库。
数据库迁移。
运行 系统检查。
运行正在测试。
报告测试次数和成功/失败。
正在删除测试数据库。
在下面的 本地测试 运行 输出 中,您可以看到这些确切的步骤,按顺序发生。问题是,在 Gitlab 的 CI/CD 管道中,第 2 步和第 4 步由于某种神秘原因被切换了。
我已经尝试过的东西
- 删除覆盖,只执行
python manage.py test
结果:同样的错误 - 删除用户测试,其中 Gitlab 表示测试失败:结果:同样的错误
- 删除除一个单元测试以外的所有单元测试以尝试隔离:结果:同样的错误
- 在 Gitlab 的容器中添加并激活虚拟环境:结果:同样的错误
- 尝试 SQLite3:结果:迁移失败,因为 SQLite3 不支持项目中必需的必要数组字段
Gitlab CI/CD 输出
我的实际产量要大得多。但这里是相关部分:
$ echo $TEST_SECRETS | base64 -d > config/settings/local.py
$ echo RUNNING UNIT TESTS
RUNNING UNIT TESTS
$ coverage run manage.py test -v 2 && coverage report
Creating test database for alias 'default' ('test_mia')...
test_dataconnector_category_creation_delete (apps.core.tests.test_models.DataConnectorCategoryTestCase)
Verify data connector category creation ... ok
test_compare_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compare object from self.airbytesetting to ensure data is in proper format. ... ok
test_fieldconstraints_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Test updating values in self.airbytesetting and saving that to the test database. ... ok
test_compare_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compare object from self.airbytesource to ensure data is in proper format. ... ok
test_delete_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test Deleting self.airbytesource object from database ... ok
test_fieldconstraints_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test updating values in self.airbytesource and saving that to the test database. ... ok
test_compare_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compare object from self.airbytestream to ensure data is in proper format. ... ok
test_delete_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test Deleting self.airbytestream object from database ... ok
test_fieldconstraints_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test updating values in self.airbytestream and saving that to the test database. ... ok
test_compare_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compare object from self.airbytesynccatalog to ensure data is in proper format. ... ok
test_delete_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test Deleting self.airbytesynccatalog object from database ... ok
test_fieldconstraints_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test updating values in self.airbytesynccatalog and saving that to the test database. ... ok
test_compare_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compare object from self.tableausetting to ensure data is in proper format. ... ok
test_createrandom_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Creating a New (Second) TableauSetting Model Object with Random Values. ... ok
test_delete_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Deleting self.tableausetting object from database ... ok
test_fieldconstraints_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test updating values in self.tableausetting and saving that to the test database. ... ok
test_get_namespace_custom_format (apps.services.tests.test_scripts_airbyte.ServicesTestCase)
TO-DO: this method should live in AirByte class ... ok
test_retrieve_me_user (apps.user.tests.test_views.UserViewTest) ... ok
test_retrieve_user (apps.user.tests.test_views.UserViewTest) ... ok
apps.user.tests.test_models (unittest.loader._FailedTest) ... ERROR
======================================================================
ERROR: apps.user.tests.test_models (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: apps.user.tests.test_models
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "user_user" does not exist
LINE 1: INSERT INTO "user_user" ("password", "last_login", "is_super...
^
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/unittest/loader.py", line 436, in _find_test_path
module = self._get_module_from_name(name)
File "/usr/local/lib/python3.8/unittest/loader.py", line 377, in _get_module_from_name
__import__(name)
File "/builds/americommerce/mia/mia-ms-main/apps/user/tests/test_models.py", line 3, in <module>
from apps.user.tests.factories import UserFactory, CompanyFactory, SignUpTokenFactory
File "/builds/americommerce/mia/mia-ms-main/apps/user/tests/factories.py", line 23, in <module>
class SignUpTokenFactory(factory.django.DjangoModelFactory):
File "/builds/americommerce/mia/mia-ms-main/apps/user/tests/factories.py", line 28, in SignUpTokenFactory
user = UserFactory()
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 40, in __call__
return cls.create(**kwargs)
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 528, in create
return cls._generate(enums.CREATE_STRATEGY, kwargs)
File "/usr/local/lib/python3.8/site-packages/factory/django.py", line 117, in _generate
return super()._generate(strategy, params)
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 465, in _generate
return step.build()
File "/usr/local/lib/python3.8/site-packages/factory/builder.py", line 262, in build
instance = self.factory_meta.instantiate(
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 317, in instantiate
return self.factory._create(model, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/factory/django.py", line 166, in _create
return manager.create(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 447, in create
obj.save(force_insert=True, using=self.db)
File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/base_user.py", line 67, in save
super().save(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 753, in save
self.save_base(using=using, force_insert=force_insert,
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 790, in save_base
updated = self._save_table(
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 895, in _save_table
results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 933, in _do_insert
return manager._insert(
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 1254, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1397, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python3.8/site-packages/sentry_sdk/integrations/django/__init__.py", line 508, in execute
return real_execute(self, sql, params)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 66, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "user_user" does not exist
LINE 1: INSERT INTO "user_user" ("password", "last_login", "is_super...
^
----------------------------------------------------------------------
Ran 25 tests in 0.648s
FAILED (errors=1)
Destroying test database for alias 'default' ('test_mia')...
Operations to perform:
Synchronize unmigrated apps: corsheaders, debug_toolbar, delete_migrations, django_filters, generic_relations, messages, mptt, rest_framework, rest_framework_jwt, rest_framework_swagger, staticfiles
Apply all migrations: admin, auth, contenttypes, core, dashboard, reports, services, sessions, store, user
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
Running migrations:
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying user.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying store.0001_initial... OK
Applying dashboard.0001_initial... OK
Applying core.0001_initial... OK
Applying reports.0001_initial... OK
Applying reports.0002_emailreport_store... OK
Applying reports.0003_initial... OK
Applying reports.0004_remove_emailreport_segments... OK
Applying core.0002_dataconnectorcategory... OK
Applying core.0003_auto_20220331_1610... OK
Applying core.0004_delete_segment... OK
Applying dashboard.0002_auto_20220331_1804... OK
Applying dashboard.0003_flag_tableauview_widget_widgetsection... OK
Applying reports.0005_emailreport_segments... OK
Applying services.0001_initial... OK
Applying services.0002_auto_20220325_0426... OK
Applying services.0003_auto_20220331_1610... OK
Applying sessions.0001_initial... OK
Applying store.0002_initial... OK
Applying store.0003_storefrontdataconnector... OK
Applying user.0002_auto_20220325_0426... OK
Applying user.0003_auto_20220331_1610... OK
Applying user.0004_auto_20220331_1804... OK
Applying user.0005_user_flags... OK
System check identified no issues (0 silenced).
Cleaning up project directory and file based variables
00:01
ERROR: Job failed: exit code 1
本地测试运行输出
Creating test database for alias 'default' ('test_mia')...
Operations to perform:
Synchronize unmigrated apps: corsheaders, debug_toolbar, delete_migrations, django_filters, generic_relations, messages, mptt, rest_framework, rest_framework_jwt, rest_framework_swagger, staticfiles
Apply all migrations: admin, auth, contenttypes, core, dashboard, reports, services, sessions, store, user
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
Running migrations:
Applying contenttypes.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0001_initial... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying user.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying store.0001_initial... OK
Applying dashboard.0001_initial... OK
Applying core.0001_initial... OK
Applying reports.0001_initial... OK
Applying reports.0002_emailreport_store... OK
Applying reports.0003_initial... OK
Applying reports.0004_remove_emailreport_segments... OK
Applying core.0002_dataconnectorcategory... OK
Applying core.0003_auto_20220331_1610... OK
Applying core.0004_delete_segment... OK
Applying dashboard.0002_auto_20220331_1804... OK
Applying dashboard.0003_flag_tableauview_widget_widgetsection... OK
Applying reports.0005_emailreport_segments... OK
Applying services.0001_initial... OK
Applying services.0002_auto_20220325_0426... OK
Applying services.0003_auto_20220331_1610... OK
Applying sessions.0001_initial... OK
Applying store.0002_initial... OK
Applying store.0003_storefrontdataconnector... OK
Applying user.0002_auto_20220325_0426... OK
Applying user.0003_auto_20220331_1610... OK
Applying user.0004_auto_20220331_1804... OK
Applying user.0005_user_flags... OK
System check identified no issues (0 silenced).
test_dataconnector_category_creation_delete (apps.core.tests.test_models.DataConnectorCategoryTestCase)
Verify data connector category creation ... ok
test_compare_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compare object from self.airbytesetting to ensure data is in proper format. ... ok
test_fieldconstraints_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Test updating values in self.airbytesetting and saving that to the test database. ... ok
test_compare_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compare object from self.airbytesource to ensure data is in proper format. ... ok
test_delete_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test Deleting self.airbytesource object from database ... ok
test_fieldconstraints_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test updating values in self.airbytesource and saving that to the test database. ... ok
test_compare_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compare object from self.airbytestream to ensure data is in proper format. ... ok
test_delete_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test Deleting self.airbytestream object from database ... ok
test_fieldconstraints_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test updating values in self.airbytestream and saving that to the test database. ... ok
test_compare_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compare object from self.airbytesynccatalog to ensure data is in proper format. ... ok
test_delete_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test Deleting self.airbytesynccatalog object from database ... ok
test_fieldconstraints_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test updating values in self.airbytesynccatalog and saving that to the test database. ... ok
test_compare_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compare object from self.tableausetting to ensure data is in proper format. ... ok
test_createrandom_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Creating a New (Second) TableauSetting Model Object with Random Values. ... ok
test_delete_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Deleting self.tableausetting object from database ... ok
test_fieldconstraints_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ... ok
test_update_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test updating values in self.tableausetting and saving that to the test database. ... ok
test_get_namespace_custom_format (apps.services.tests.test_scripts_airbyte.ServicesTestCase)
TO-DO: this method should live in AirByte class ... ok
test_company_creation (apps.user.tests.test_models.UserTestCase)
Verify Company creation ... ok
test_signup_token_creation (apps.user.tests.test_models.UserTestCase)
Verify token creation ... ok
test_user_creation (apps.user.tests.test_models.UserTestCase)
Verify User creation ... ok
test_user_creation_with_company (apps.user.tests.test_models.UserTestCase)
Verify User can be assigned company ... ok
test_user_creation_with_signup_token (apps.user.tests.test_models.UserTestCase)
Verify User can be assigned token ... ok
test_retrieve_me_user (apps.user.tests.test_views.UserViewTest) ... ok
test_retrieve_user (apps.user.tests.test_views.UserViewTest) ... ok
----------------------------------------------------------------------
Ran 29 tests in 0.521s
OK
Destroying test database for alias 'default' ('test_mia')...
Name Stmts Miss Cover
---------------------------------------------------------------------
apps/core/admin.py 5 0 100%
apps/core/exceptions.py 22 3 86%
apps/core/mixins.py 10 3 70%
apps/core/models.py 8 1 88%
apps/core/serializers.py 18 0 100%
apps/core/urls.py 5 0 100%
apps/core/utils.py 69 33 52%
apps/core/views.py 42 26 38%
apps/dashboard/admin.py 15 0 100%
apps/dashboard/models.py 34 7 79%
apps/dashboard/urls.py 6 0 100%
apps/dashboard/views.py 27 16 41%
apps/delete_migrations/admin.py 1 0 100%
apps/delete_migrations/models.py 1 0 100%
apps/reports/admin.py 14 0 100%
apps/reports/mixins.py 16 9 44%
apps/reports/models/alert.py 47 3 94%
apps/reports/models/email_report.py 31 1 97%
apps/reports/serializers/alert.py 49 14 71%
apps/reports/serializers/email_report.py 49 22 55%
apps/reports/tasks.py 71 43 39%
apps/reports/urls.py 9 0 100%
apps/reports/utils.py 12 9 25%
apps/reports/views/alerts.py 40 23 42%
apps/reports/views/reports.py 55 26 53%
apps/services/admin.py 23 6 74%
apps/services/models/airbyte.py 37 0 100%
apps/services/models/tableau.py 9 0 100%
apps/services/scripts/airbyte.py 157 126 20%
apps/services/scripts/tableau.py 69 50 28%
apps/services/urls.py 3 0 100%
apps/services/views.py 15 8 47%
apps/store/admin.py 41 0 100%
apps/store/mixins.py 12 7 42%
apps/store/models/amazon_ads.py 18 2 89%
apps/store/models/amazon_seller_partner.py 21 2 90%
apps/store/models/data_connector_base.py 28 5 82%
apps/store/models/data_connector_settings.py 18 3 83%
apps/store/models/facebook.py 17 2 88%
apps/store/models/google_ads.py 20 2 90%
apps/store/models/google_analytics.py 18 2 89%
apps/store/models/google_search_console.py 18 2 89%
apps/store/models/hubspot.py 14 2 86%
apps/store/models/klaviyo.py 12 1 92%
apps/store/models/mailchimp.py 14 2 86%
apps/store/models/shopify.py 17 2 88%
apps/store/models/store.py 13 3 77%
apps/store/models/storefront.py 19 8 58%
apps/store/serializers/amazon_ads.py 22 11 50%
apps/store/serializers/amazon_seller_partner.py 26 14 46%
apps/store/serializers/base.py 8 0 100%
apps/store/serializers/credentials.py 3 0 100%
apps/store/serializers/facebook.py 15 7 53%
apps/store/serializers/google_ads.py 23 12 48%
apps/store/serializers/google_analytics.py 22 11 50%
apps/store/serializers/google_search_console.py 22 11 50%
apps/store/serializers/hubspot.py 6 0 100%
apps/store/serializers/klaviyo.py 6 0 100%
apps/store/serializers/list_data_connectors.py 24 0 100%
apps/store/serializers/mailchimp.py 6 0 100%
apps/store/serializers/shopify.py 21 10 52%
apps/store/serializers/store.py 30 3 90%
apps/store/serializers/storefront.py 6 0 100%
apps/store/tasks.py 104 80 23%
apps/store/urls.py 26 0 100%
apps/store/utils.py 89 66 26%
apps/store/views/check_data_connector_store.py 21 13 38%
apps/store/views/credentials.py 13 3 77%
apps/store/views/delete_data_connector.py 19 10 47%
apps/store/views/detail_data_connectors.py 42 0 100%
apps/store/views/list_data_connectors.py 50 32 36%
apps/store/views/reset_data_connector.py 18 9 50%
apps/store/views/store.py 15 8 47%
apps/store/views/sync_data_connector.py 18 9 50%
apps/user/admin.py 29 7 76%
apps/user/apps.py 5 0 100%
apps/user/forms.py 14 1 93%
apps/user/models.py 72 13 82%
apps/user/serializers.py 88 31 65%
apps/user/signals.py 11 4 64%
apps/user/tasks.py 15 6 60%
apps/user/urls.py 7 0 100%
apps/user/utils.py 4 0 100%
apps/user/validators.py 7 2 71%
apps/user/views.py 61 26 57%
manage.py 13 6 54%
---------------------------------------------------------------------
TOTAL 2250 879 61%
.gitlab-ci.yml 文件
我的实际文件要大得多。但这里是相关部分:
services:
- docker:20.10.7-dind
- postgres:latest
stages:
- test
variables:
POSTGRES_DB: test_mia
POSTGRES_USER: mia_dev
POSTGRES_PASSWORD: test123
build_test_db:
image: postgres
script:
- export PGPASSWORD=$POSTGRES_PASSWORD
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT 'OK' AS status;"
test:
image: python:3.8-slim-buster
stage: test
before_script:
- |
apt-get update && apt-get install -y --no-install-recommends \
gcc \
musl-dev \
python3-dev \
libpq-dev \
libgnutls28-dev \
git \
&& rm -rf /var/lib/apt/lists/*
- python -m pip install --upgrade pip
- pip install uwsgi
- pip install -r requirements.txt
- echo $TEST_SECRETS | base64 -d > config/settings/local.py
script:
- echo RUNNING UNIT TESTS
- coverage run manage.py test -v 2 && coverage report
needs:
- ["build_test_db"]
environment: test
# only:
# - develop
在 gitlab-ci.yml
的脚本部分的 coverage run manage.py test ...
之前添加 python manage.py migrate
行。