title: Gitlab CI/CD Pipeline Runs Django Unit Tests Before Migrations
body: <h1>Problem</h1>
  <p>I'm trying to set up a test stage in Gitlab's CI/CD. Locally, running the unit tests goes fine and as expected. In Gitlab's CI/CD, though, when running the script <code>coverage run manage.py test -v 2 &amp;&amp; coverage report</code> the unit tests are executing <em><strong>before</strong></em> the migrations are completed in the test database, which is unexpected, and will always fail. Migrations on the test database need to run prior to unit tests executing.</p>
  <p>Any idea why this behavior might happen?</p>
  <p>When running <code>python manage.py test</code> these are the steps that happen by default:</p>
  <ol>
  <li><p>Creation of test databases.</p>
  </li>
  <li><p>Database migration.</p>
  </li>
  <li><p>Run system checks.</p>
  </li>
  <li><p>Running tests.</p>
  </li>
  <li><p>Report on the number of tests and success / failure.</p>
  </li>
  <li><p>Removing test databases.</p>
  </li>
  </ol>
  <p>In the <strong>local test run output</strong> below, you can see those exact steps, in that sequence happening. The problem is that in <strong>Gitlab's CI/CD</strong> pipeline, step 2 and 4 are switched for some mysterious reason to me.</p>
  <h1>Things I've already tried</h1>
  <ul>
  <li>Removing coverage, and only executing <code>python manage.py test</code> Result: same error</li>
  <li>Removing user test, where Gitlab says the test fails: Result: same error</li>
  <li>Removing all but one unit test to attempt to isolate: Result: same error</li>
  <li>Adding and activating a virtual environment inside Gitlab's container: Result: same error</li>
  <li>Trying a SQLite3: Result: migrations fail due to necessary array field necessary in the project not supported in SQLite3</li>
  </ul>
  <h1>Gitlab CI/CD Output</h1>
  <p>My actual output is much bigger. But here's the relevant parts:</p>
  <pre><code>$ echo $TEST_SECRETS | base64 -d &gt; config/settings/local.py
  $ echo RUNNING UNIT TESTS
  RUNNING UNIT TESTS
  $ coverage run manage.py test -v 2 &amp;&amp; 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 &quot;/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py&quot;, line 84, in _execute
      return self.cursor.execute(sql, params)
  psycopg2.errors.UndefinedTable: relation &quot;user_user&quot; does not exist
  LINE 1: INSERT INTO &quot;user_user&quot; (&quot;password&quot;, &quot;last_login&quot;, &quot;is_super...
                      ^
  The above exception was the direct cause of the following exception:
  Traceback (most recent call last):
    File &quot;/usr/local/lib/python3.8/unittest/loader.py&quot;, line 436, in _find_test_path
      module = self._get_module_from_name(name)
    File &quot;/usr/local/lib/python3.8/unittest/loader.py&quot;, line 377, in _get_module_from_name
      __import__(name)
    File &quot;/builds/americommerce/mia/mia-ms-main/apps/user/tests/test_models.py&quot;, line 3, in &lt;module&gt;
      from apps.user.tests.factories import UserFactory, CompanyFactory, SignUpTokenFactory
    File &quot;/builds/americommerce/mia/mia-ms-main/apps/user/tests/factories.py&quot;, line 23, in &lt;module&gt;
      class SignUpTokenFactory(factory.django.DjangoModelFactory):
    File &quot;/builds/americommerce/mia/mia-ms-main/apps/user/tests/factories.py&quot;, line 28, in SignUpTokenFactory
      user = UserFactory()
    File &quot;/usr/local/lib/python3.8/site-packages/factory/base.py&quot;, line 40, in __call__
      return cls.create(**kwargs)
    File &quot;/usr/local/lib/python3.8/site-packages/factory/base.py&quot;, line 528, in create
      return cls._generate(enums.CREATE_STRATEGY, kwargs)
    File &quot;/usr/local/lib/python3.8/site-packages/factory/django.py&quot;, line 117, in _generate
      return super()._generate(strategy, params)
    File &quot;/usr/local/lib/python3.8/site-packages/factory/base.py&quot;, line 465, in _generate
      return step.build()
    File &quot;/usr/local/lib/python3.8/site-packages/factory/builder.py&quot;, line 262, in build
      instance = self.factory_meta.instantiate(
    File &quot;/usr/local/lib/python3.8/site-packages/factory/base.py&quot;, line 317, in instantiate
      return self.factory._create(model, *args, **kwargs)
    File &quot;/usr/local/lib/python3.8/site-packages/factory/django.py&quot;, line 166, in _create
      return manager.create(*args, **kwargs)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/models/manager.py&quot;, line 85, in manager_method
      return getattr(self.get_queryset(), name)(*args, **kwargs)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/models/query.py&quot;, line 447, in create
      obj.save(force_insert=True, using=self.db)
    File &quot;/usr/local/lib/python3.8/site-packages/django/contrib/auth/base_user.py&quot;, line 67, in save
      super().save(*args, **kwargs)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/models/base.py&quot;, line 753, in save
      self.save_base(using=using, force_insert=force_insert,
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/models/base.py&quot;, line 790, in save_base
      updated = self._save_table(
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/models/base.py&quot;, line 895, in _save_table
      results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/models/base.py&quot;, line 933, in _do_insert
      return manager._insert(
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/models/manager.py&quot;, line 85, in manager_method
      return getattr(self.get_queryset(), name)(*args, **kwargs)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/models/query.py&quot;, line 1254, in _insert
      return query.get_compiler(using=using).execute_sql(returning_fields)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py&quot;, line 1397, in execute_sql
      cursor.execute(sql, params)
    File &quot;/usr/local/lib/python3.8/site-packages/sentry_sdk/integrations/django/__init__.py&quot;, line 508, in execute
      return real_execute(self, sql, params)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py&quot;, line 66, in execute
      return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py&quot;, line 75, in _execute_with_wrappers
      return executor(sql, params, many, context)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py&quot;, line 84, in _execute
      return self.cursor.execute(sql, params)
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/utils.py&quot;, line 90, in __exit__
      raise dj_exc_value.with_traceback(traceback) from exc_value
    File &quot;/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py&quot;, line 84, in _execute
      return self.cursor.execute(sql, params)
  django.db.utils.ProgrammingError: relation &quot;user_user&quot; does not exist
  LINE 1: INSERT INTO &quot;user_user&quot; (&quot;password&quot;, &quot;last_login&quot;, &quot;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
  
  </code></pre>
  <h1>Local Test Run Output</h1>
  <pre><code>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%
  
  </code></pre>
  <h1>.gitlab-ci.yml file</h1>
  <p>My actual file is much bigger. But here's the relevant parts:</p>
  <pre><code>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 &quot;postgres&quot; -U &quot;$POSTGRES_USER&quot; -d &quot;$POSTGRES_DB&quot; -c &quot;SELECT 'OK' AS status;&quot;
  
  test:
      image: python:3.8-slim-buster
      stage: test
      before_script:
          - |
              apt-get update &amp;&amp; apt-get install -y --no-install-recommends \
              gcc \
              musl-dev \
              python3-dev \
              libpq-dev \
              libgnutls28-dev \
              git \
              &amp;&amp; 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 &gt; config/settings/local.py
      script:
          - echo RUNNING UNIT TESTS
          - coverage run manage.py test -v 2 &amp;&amp; coverage report
      needs:
          - [&quot;build_test_db&quot;]
      environment: test
      # only:
      #     - develop
  
  
  </code></pre>