【问题标题】:How do I fix IntegrityErrors during the Django TestCase teardown?如何在 Django TestCase 拆解期间修复 IntegrityErrors?
【发布时间】:2019-04-10 13:35:37
【问题描述】:

我正在将一个大型 web 应用程序从 Python 2.7 移植到 Python 3.6。我已经管理了数据库迁移并使用 2to3 转换了代码,但是我在运行我的测试套件时遇到了问题。对于大量测试,我得到如下错误:

  62 self = <django.db.backends.utils.CursorWrapper object at 0x7fc7d0abbeb8>
  63 sql = 'SET CONSTRAINTS ALL IMMEDIATE', params = None
  64 
  65     def execute(self, sql, params=None):
  66         self.db.validate_no_broken_transaction()
  67         with self.db.wrap_database_errors:
  68             if params is None:
  69 >               return self.cursor.execute(sql)
  70 E               psycopg2.IntegrityError: insert or update on table "probex_historicalproject" violates forei
     gn key constraint "probex_historicalpro_history_user_id_88371c5c_fk_auth_user"
  71 E               DETAIL:  Key (history_user_id)=(303) is not present in table "auth_user".
  72 
  73 ../../venv3/lib/python3.6/site-packages/django/db/backends/utils.py:62: IntegrityError
  74 
  75 The above exception was the direct cause of the following exception:
  76 
  77 self = <django.test.testcases.TestCase testMethod=__init__>
  78 
  79     def _post_teardown(self):
  80         """Performs any post-test things. This includes:
  81 
  82             * Flushing the contents of the database, to leave a clean slate. If
  83               the class has an 'available_apps' attribute, post_migrate isn't fired.
  84             * Force-closing the connection, so the next test gets a clean cursor.
  85             """
  86         try:
  87 >           self._fixture_teardown()
  88 
  89 ../../venv3/lib/python3.6/site-packages/django/test/testcases.py:925:
  90 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  91 ../../venv3/lib/python3.6/site-packages/django/test/testcases.py:1081: in _fixture_teardown
  92     connections[db_name].check_constraints()
  93 ../../venv3/lib/python3.6/site-packages/django/db/backends/postgresql/base.py:243: in check_constraints
  94     self.cursor().execute('SET CONSTRAINTS ALL IMMEDIATE')
  95 ../../venv3/lib/python3.6/site-packages/raven/contrib/django/client.py:127: in execute
  96     return real_execute(self, sql, params)
  97 ../../venv3/lib/python3.6/site-packages/django/db/backends/utils.py:64: in execute                          
  98     return self.cursor.execute(sql, params)                                                                 
  99 ../../venv3/lib/python3.6/site-packages/django/db/utils.py:94: in __exit__                                  
 100     six.reraise(dj_exc_type, dj_exc_value, traceback)                                                       
 101 ../../venv3/lib/python3.6/site-packages/django/utils/six.py:685: in reraise
 102     raise value.with_traceback(tb)
 103 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

我尝试在我同事的一些机器上运行测试,有些人运行测试没有问题,但有些人和我有同样的问题。

另外值得注意的是:如果我自己运行单个测试文件(即py.test /path/to/file),则不会发生此错误。我认为这一定与测试之间处理数据库数据的方式有关。

这是一个失败的示例测试:

  1 
  2 from django.utils import timezone
  3 from tests.tests_probex.tests_python.testing_utilities import LoggedInTestCase
  4 from tests.tests_probex.tests_python.factories import JobFactory
  5 from probex.models import Profile, Tenant, Job
  6 from probex.views.reports import build_tenant_report
  7 from django.contrib.auth.models import User
  8 import pytest
  9 
 10 pytestmark = pytest.mark.xfail(reason="Not working in Python 3.6")
 11                                                                                                                             
 12                                                                                                                             
 13 class TestTenantReport(LoggedInTestCase):                                                                                   
 14     def setUp(self):                                                                                                        
 15         super(TestTenantReport, self).setUp()                                                                               
 16         self.end_date = timezone.now()                                                                                      
 17         self.delta = timezone.timedelta(days=7)                                                                             
 18         self.start_date = self.end_date - self.delta                                                                        
 19                                                                                                                             
 20         self.date = timezone.now() - timezone.timedelta(days=3)                                                             
 21         self.job = JobFactory(absolute_num=1600, relative_num=1600, protocol=self.protocol, project=self.project, status='Co
    mplete', created=self.date, submitter_id=self.user.id)                                                                      
 22                                                                                                                             
 23     def test_returns_new_users(self):                                                                                       
 24         users = User.objects.all()                                                                                          
 25         for user in users:                                                                                                  
 26             user.date_joined = self.date                                                                                    
 27             p = Profile.objects.get(user_id=user.id)                                                                        
 28             tenant = Tenant.objects.get(id=p.tenant_id)                                                                     
 29             tenant.app_scientist = self.user                                                                                
 30             user.save()                                                                                                     
 31             tenant.save()                                                                                                   
 32                                                                                                                             
 33         report = build_tenant_report(self.user)                                                                             
 34         self.assertGreaterEqual(report['new_users'].count(), users.count()) 

LoggedInTestCase 是 django TestCase 的子类:

 15 class LoggedInTestCase(TestCase):
 16     def setUp(self):
 17         self.user = User.objects.create_user(username='dummy@hotmail.com', email='dummy@hotmail.com', password="secret123")
 18         self.user.user_permissions.add(Permission.objects.get(codename='add_job'))
 19         self.user.user_permissions.add(Permission.objects.get(codename='change_job'))
 20         self.user.user_permissions.add(Permission.objects.get(codename='add_project'))
 21         self.user.user_permissions.add(Permission.objects.get(codename='add_user'))
 22         self.user.user_permissions.add(Permission.objects.get(codename='change_user'))                                                               
 23         self.tenant = Tenant.objects.create(name="testtenant")                                                                                       
 24         self.user.profile.tenant = self.tenant                                                                                                       
 25         self.user.profile.save()                                                                                                                     
 26         self.project = ProjectFactory(name="testproject", tenant=self.tenant, active=True, identifier='AAA')                                         
 27         self.protocol = ProtocolFactory()                                                                                                            
 28         self.root_term = TermFactory(is_root=True, acc='all')                                                                                        
 29         self.login()                                                                                                                                 
 30                                                                                                                                                      
 31     def login(self):                                                                                                                                 
 32         self.client.login(username='dummy@hotmail.com', password='secret123')                                                                        
 33                                                                                                                                                      
 34     def logout(self):                                                                                                                                
 35         self.client.logout()                                                                                                                         
 36                                                                                                                                                      
 37     def get_user(self):                                                                                                                              
 38         return self.client                                                                                                                           
 39                                                                                                                                                      
 40     def permission_restricted(self, response, first_stop_url):                                                                                       
 41         first_redirect, status_1 = response.redirect_chain[0]                                                                                        
 42         second_redirect, status_2 = response.redirect_chain[1]                                                                                       
 43         self.assertEqual(first_redirect, first_stop_url)                                                                                             
 44         self.assertEqual(status_1, 302)                                                                                                              
 45         self.assertEqual(second_redirect, reverse('home'))                                                                                           
 46         self.assertEqual(status_2, 302)   

这些测试通常在 Python 2.7 下运行时通过,除了更新到 3.6 之外,我没有太大变化。我仍然希望他们现在通过。如果有人有任何指示,我将不胜感激。第一次在这里发布海报。

【问题讨论】:

  • 我们能看到LoggedInTestCase吗?
  • @Franey 是的,我已经在上面添加了 LoggedInTestCase 的详细信息

标签: django python-3.x pytest


【解决方案1】:

对于任何偶然发现这一点的人:提示在被违反的键中。 historicalprojecthistory_userdjango-simple-history 包相关。我们最终更新了我们的工厂男孩发电机,还包括了一个历史工厂。这解决了问题。

【讨论】:

    【解决方案2】:

    我在使用django-simple-history 库时也遇到了这个问题。事实证明,我们的问题是由于在不同的数据库中有多个相互依赖的模型造成的。为了进行测试,我们更改了数据库路由器以将所有模型设置为在同一个数据库中创建,这为我们解决了IntegrityError。我认为将历史和模型放在不同的数据库中也可能是个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-29
      • 2020-02-09
      • 2017-03-11
      • 2011-11-22
      • 2012-10-01
      相关资源
      最近更新 更多