You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django测试本地正常但GitHub Actions执行失败求助

Django测试用例本地正常但GitHub Actions未触发DataError的问题

我有2个Django测试用例在本地运行完全正常,但在GitHub Actions中执行失败(Python 3.9版本)。具体是测试名称过长和CUIT过长导致创建失败的用例,本地能正常触发DataError,但GitHub Actions中报错提示DataError not raised。


依赖文件(requirements.txt)

Django==4.1.7
django-crum==0.7.9
django-widget-tweaks==1.4.12
et-xmlfile==1.0.1
flake8==5.0.4
openpyxl==3.0.10
pandas==1.5.1
Pillow==9.3.0
python-dotenv==0.19.0
XlsxWriter==1.1.5
xmltodict==0.13.0

模型代码

class Empresa(models.Model):
    name = models.CharField(max_length=120, verbose_name='Razon Social')
    cuit = models.CharField(max_length=11, validators=[MinLengthValidator(11)])
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return self.name

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        if not self.user:
            user = get_current_user()
            if user and not user.pk:
                user = None
            if not self.pk:
                self.user = user
            self.user = user
        return super().save(force_insert, force_update, using, update_fields)

    def toJSON(self):
        item = model_to_dict(self)
        return item

测试用例说明

  • 成功创建Empresa实例:测试正常通过
  • 名称过长导致创建失败:本地正常,GitHub Actions中失败
  • CUIT过长导致创建失败:本地正常,GitHub Actions中失败

测试代码

class EmpresaTesting(TestCase):

    def setUp(self):
        self.client = Client()

        self.user = User.objects.create(username='testuser', password='12345')
        self.user.save()

    def test_create_empresa_ok(self):
        this_empresa = Empresa.objects.create(name='Empresa 1', cuit='30999999991', user=self.user)
        self.assertTrue(isinstance(this_empresa, Empresa))
        self.assertEqual(str(this_empresa), 'Empresa 1')

    def test_create_empresa_long_name(self):
        long_name = "a" * 121
        with self.assertRaisesMessage(DataError, "Data too long for column 'name' at row 1"):
            Empresa.objects.create(name=long_name, cuit='30999999991', user=self.user)

    def test_create_empresa_long_cuit(self):
        with self.assertRaisesMessage(DataError, "Data too long for column 'cuit' at row 1"):
            Empresa.objects.create(name="Empresa 1", cuit='123456789012', user=self.user)

GitHub Actions报错信息

FAIL: test_create_empresa_long_cuit (export_lsd.tests.EmpresaTesting)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/work/el_conta/el_conta/export_lsd/tests.py", line 28, in test_create_empresa_long_cuit
    Empresa.objects.create(name="Empresa 1", cuit='123456789012', user=self.user)
  File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/contextlib.py", line 126, in __exit__
    next(self.gen)
  File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/django/test/testcases.py", line 876, in _assert_raises_or_warns_cm
    yield cm
AssertionError: DataError not raised

======================================================================
FAIL: test_create_empresa_long_name (export_lsd.tests.EmpresaTesting)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/work/el_conta/el_conta/export_lsd/tests.py", line 24, in test_create_empresa_long_name
    Empresa.objects.create(name=long_name, cuit='30999999991', user=self.user)
  File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/contextlib.py", line 126, in __exit__
    next(self.gen)
  File "/opt/hostedtoolcache/Python/3.9.16/x64/lib/python3.9/site-packages/django/test/testcases.py", line 876, in _assert_raises_or_warns_cm
    yield cm
AssertionError: DataError not raised

GitHub Actions工作流配置

name: Django CI

on:
  push:
    branches: [ "develop" ]
  pull_request:
    branches: [ "develop" ]

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      max-parallel: 4
      matrix:
        python-version: [3.8, 3.9]

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v3
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install Dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
        
    - name: Check pending migrations
      run: |
        python manage.py makemigrations --check --dry-run
        python manage.py migrate
    
    - name: Lint with Flake8
      run: |
        flake8 --count --show-source --max-complexity=10 --max-line-length=130 --statistics --ignore=C901,F811
    - name: Run Tests
      run: |
        python manage.py test

问题原因与解决方法

核心原因

本地和GitHub Actions使用的数据库行为不一致:

  • 本地大概率使用MySQL/PostgreSQL这类严格模式的数据库,当字段长度超出限制时会直接抛出DataError。
  • GitHub Actions默认使用SQLite,SQLite的默认策略是自动截断过长的字符串而不是抛出错误,这就导致测试用例中的assertRaisesMessage无法捕获到预期的异常。

解决方案

方案1:修改测试用例,依赖Django ORM层验证(推荐)

不要依赖数据库层面的错误,而是在模型中添加自定义验证逻辑,在ORM层拦截非法数据,这样跨数据库环境都能稳定运行。

  1. 给Empresa模型添加clean()方法:
from django.core.exceptions import ValidationError

class Empresa(models.Model):
    # 原有字段定义...
    
    def clean(self):
        # 验证名称长度
        if len(self.name) > 120:
            raise ValidationError({"name": "名称长度不能超过120个字符"})
        # 验证CUIT长度
        if len(self.cuit) != 11:
            raise ValidationError({"cuit": "CUIT必须是11位字符"})
  1. 修改测试用例,触发ORM验证并捕获ValidationError:
def test_create_empresa_long_name(self):
    long_name = "a" * 121
    with self.assertRaisesMessage(ValidationError, "名称长度不能超过120个字符"):
        empresa = Empresa(name=long_name, cuit='30999999991', user=self.user)
        empresa.full_clean()  # 触发模型的clean验证
        empresa.save()

def test_create_empresa_long_cuit(self):
    with self.assertRaisesMessage(ValidationError, "CUIT必须是11位字符"):
        empresa = Empresa(name="Empresa 1", cuit='123456789012', user=self.user)
        empresa.full_clean()
        empresa.save()

方案2:在GitHub Actions中使用和本地一致的数据库

如果必须依赖数据库层面的错误,可以在GitHub Actions中配置和本地相同的数据库(比如MySQL/PostgreSQL)。

以MySQL为例,修改工作流配置:

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      max-parallel: 4
      matrix:
        python-version: [3.8, 3.9]
    # 添加MySQL服务
    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: test_db
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=5
    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v3
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install Dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt mysqlclient  # 安装MySQL驱动
    - name: Configure Database
      run: |
        # 设置环境变量,让Django连接MySQL
        echo "DATABASE_NAME=test_db" >> $GITHUB_ENV
        echo "DATABASE_USER=root" >> $GITHUB_ENV
        echo "DATABASE_PASSWORD=root" >> $GITHUB_ENV
        echo "DATABASE_HOST=127.0.0.1" >> $GITHUB_ENV
        echo "DATABASE_PORT=3306" >> $GITHUB_ENV
    - name: Check pending migrations
      run: |
        python manage.py makemigrations --check --dry-run
        python manage.py migrate
    # 后续lint、测试步骤不变...

同时修改项目的settings.py,根据环境变量配置数据库:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': os.getenv('DATABASE_NAME', 'local_db'),
        'USER': os.getenv('DATABASE_USER', 'root'),
        'PASSWORD': os.getenv('DATABASE_PASSWORD', ''),
        'HOST': os.getenv('DATABASE_HOST', '127.0.0.1'),
        'PORT': os.getenv('DATABASE_PORT', '3306'),
        'OPTIONS': {
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",  # 开启严格模式
        },
    }
}

内容的提问来源于stack exchange,提问作者Eugenio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 08:17:05