1

Я пытаюсь запустить функциональные тесты, используя Selenium для проекта Django. Как в Firefox, так и в Chrome я получаю странную ошибку внешнего ключа, когда я пытаюсь проверить, что суперпользователь может изменить статус обычного пользователя для персонала (я предполагаю, что все это проверено с помощью внутреннего тестирования Django, но подумал, что было бы хорошей практикой включить это в тестировании моего приложения, поскольку мои пользовательские сценарии зависят от функциональности). Похоже, что Django не любит, что Selenium ничего не сохраняет в базе данных? Эта одна ошибка также просачивается в мои другие тесты, поэтому кажется, что что-то ломается за кулисами - например, Selenium теряет соединение с базой данных. Кто-нибудь знает, почему это произошло?? Я готов свалить тест в пользу того, что функция работает, но хотелось бы исправить это и использовать тест.Selenium/Django дает ошибку внешнего ключа

Один из возможных симптомов заключается в том, что в Chrome между выводами «отмечен флажок» и «нажата кнопка сохранения», я получаю сломанную трубку (в Firefox не работает).

Кажется ломаться здесь, когда Селен нажимает на кнопку 'Сохранить':

# Form looks properly rendered, now click the 'Staff status' 
# checkbox and submit it 
isStaffCheckbox = self.browser.find_element_by_id('id_is_staff') 
isStaffCheckbox.click()    
print 'checked the box' 
# Save the form 
saveBtn = self.browser.find_element_by_css_selector('input[value="Save"]') 
saveBtn.click() 
print 'clicked the save button' 

Сообщение об ошибке я получаю это:

Traceback (most recent call last): 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/test/testcases.py", line 268, in __call__ 
    self._post_teardown() 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/test/testcases.py", line 533, in _post_teardown 
    self._fixture_teardown() 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/test/testcases.py", line 553, in _fixture_teardown 
    skip_validation=True, reset_sequences=False) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/core/management/__init__.py", line 161, in call_command 
    return klass.execute(*args, **defaults) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/core/management/base.py", line 255, in execute 
    output = self.handle(*args, **options) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/core/management/base.py", line 385, in handle 
    return self.handle_noargs(**options) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/core/management/commands/flush.py", line 82, in handle_noargs 
    emit_post_sync_signal(set(all_models), verbosity, interactive, db) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/core/management/sql.py", line 195, in emit_post_sync_signal 
    interactive=interactive, db=db) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/dispatch/dispatcher.py", line 170, in send 
    response = receiver(signal=self, sender=sender, **named) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/contrib/auth/management/__init__.py", line 96, in create_permissions 
    auth_app.Permission.objects.using(db).bulk_create(perms) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/db/models/query.py", line 444, in bulk_create 
    self._batched_insert(objs_without_pk, fields, batch_size) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/db/models/query.py", line 902, in _batched_insert 
    using=self.db) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/db/models/manager.py", line 215, in _insert 
    return insert_query(self.model, objs, fields, **kwargs) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/db/models/query.py", line 1661, in insert_query 
    return query.get_compiler(using=using).execute_sql(return_id) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 937, in execute_sql 
    cursor.execute(sql, params) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/db/backends/mysql/base.py", line 122, in execute 
    six.reraise(utils.IntegrityError, utils.IntegrityError(*tuple(e.args)), sys.exc_info()[2]) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/django/db/backends/mysql/base.py", line 120, in execute 
    return self.cursor.execute(query, args) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/MySQL_python-1.2.4b4-py2.7-macosx-10.8-intel.egg/MySQLdb/cursors.py", line 202, in execute 
    self.errorhandler(self, exc, value) 
File "/Users/cjshaw/Documents/virtual_environments/VideoSearch/lib/python2.7/site-packages/MySQL_python-1.2.4b4-py2.7-macosx-10.8-intel.egg/MySQLdb/connections.py", line 36, in defaulterrorhandler 
    raise errorclass, errorvalue 
IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (`test_videos2002`.`auth_permission`, CONSTRAINT `content_type_id_refs_id_d043b34a` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`))') 

===== Изменено с кодом

  • Также обратите внимание, что test_admin_can_make_a_user_staff вызывает другие мои тесты с ошибкой с тем же адресом ror - но они в порядке, когда я вынимаю команду «save» из этого теста.
  • Я предполагаю, что две вещи, которые я действительно не понимаю, это: 1) Почему это происходит со встроенным администраторским представлением Django (подумал, что это должно сработать) и 2) Почему одна тестовая ошибка каскадируется до моих других тестов? Я думал, что они независимы.

Спасибо, что посмотрели на это!

С моего functional_tests.test.py (заимствовано из https://github.com/lincolnloop/django-selenium-intro/tree/master/selenium_intro):

from django.test import LiveServerTestCase 

class SeleniumTestCase(LiveServerTestCase): 
    """ 
    A base test case for selenium, providing hepler methods for generating 
    clients and logging in profiles. 
    """ 

    def open(self, url): 
     self.browser.get("%s%s" % (self.live_server_url, url)) 

С моего admin_django.py (набор тестов)

from functional_tests.test import SeleniumTestCase 

from selenium.webdriver.common.keys import Keys 
from django.core.urlresolvers import reverse 
from django.contrib.auth.models import User 
from django.test import LiveServerTestCase 
from django.conf import settings 
from selenium import webdriver 


class AdminDjango(SeleniumTestCase): 
    def setUp(self): 
     User.objects.create_superuser(username='vcb', 
             password='rock5!', 
             email='[email protected]') 
     User.objects.create_user(username='teaching', 
           password='assistant', 
           email='[email protected]') 
#  self.browser = webdriver.Chrome(settings.SELENIUM_WEBDRIVER) 
     self.browser = webdriver.Firefox() 
     self.browser.implicitly_wait(3) 
     self.browser.set_page_load_timeout(10) 

    def tearDown(self): 
     self.browser.quit() 

    def check_for_links(self, link_text): 
     """ 
     Helper function to check links on a page for certain text 
     """ 
     links = self.browser.find_elements_by_tag_name('a') 
     self.assertTrue(link_text, [link.text for link in links]) 

    def admin_logs_in(self): 
     """ 
     Helper function that logs the admin user into the page 
     """ 
     username_field = self.browser.find_element_by_name('username') 
     username_field.send_keys('vcb') 

     password_field = self.browser.find_element_by_name('password') 
     password_field.send_keys('rock5!') 
     password_field.send_keys(Keys.RETURN) 

    def admin_log_in_complete(self): 
     """ 
     Includes navigation to the admin page 
     """ 
     self.open('/admin/') 
     self.admin_logs_in() 

    def test_admin_can_login(self): 
     """ 
     Admin user can log into the Django admin interface 
     """ 
     self.open('/admin/') 
     body = self.browser.find_element_by_tag_name('body') 
     self.assertIn('VCB Administration', body.text) 

     self.admin_logs_in() 

     # her username and password are accepted, and she is taken to 
     # the Site Administration page 
     body = self.browser.find_element_by_tag_name('body') 
     self.assertIn('Site administration', body.text) 

    def test_admin_page_renders_properly(self): 
     """ 
     The admin page should have at least two fields: 
     - Users 
     - Classes 
     Admins may have to add staff status to users, and they may have to 
     adjust the information for a class 
     """ 
     self.admin_log_in_complete() 

     self.check_for_links('Users') 
     self.check_for_links('Groups') 
     self.check_for_links('Classess') 

    def test_admin_can_make_a_user_staff(self): 
     """ 
     Admin users can add staff status to existing users 
     """ 
     self.admin_log_in_complete() 
     pageLinks = self.browser.find_elements_by_tag_name('a') 

     for link in pageLinks: 
      if link.text == 'Users': 
       userLink = link 

     userLink.click() 

     headers = self.browser.find_elements_by_tag_name('h1') 
     self.assertTrue('Select user to change', 
       [header.text for header in headers]) 

     users =  self.browser.find_elements_by_xpath('//table[@id="result_list"]/tbody/tr/th/a') 

     self.fail('Finish writing the test!') 
#  rowCount = 1 
#  for user in users: 
#   xpath = '//table[@id="result_list"]/tbody/tr[' + str(rowCount) + ']/td[5]/img' 
#   # check first that this user is not a staff 
#   staffIcon = self.browser.find_element_by_xpath(xpath) 
#   isStaff = staffIcon.get_attribute('alt') 
#    
#   if isStaff == 'false': 
#    user.click() 
#    userHeaders = self.browser.find_elements_by_tag_name('h1') 
#    self.assertTrue('Change user', 
#      [userHeader.text for userHeader in userHeaders]) 
#    
#    # Are the right fields present in the user's form? 
#    formHeaders = self.browser.find_elements_by_tag_name('h2') 
#    self.assertTrue('Personal info', 
#      [formHeader.text for formHeader in formHeaders]) 
#    self.assertTrue('Permissions', 
#      [formHeader.text for formHeader in formHeaders]) 
#    self.assertTrue('Important dates', 
#      [formHeader.text for formHeader in formHeaders]) 
#    
#    # Form looks properly rendered, now click the 'Staff status' 
#    # checkbox and submit it 
#    isStaffCheckbox = self.browser.find_element_by_id('id_is_staff') 
#    isStaffCheckbox.click() 
#    print 'checked the box' 
#    # Save the form 
#    saveBtn = self.browser.find_element_by_css_selector('input[value="Save"]') 
#    saveBtn.click() 
#    print 'clicked the save button' 
#    # Returns you to the admin page 
#    messageBox = self.browser.find_element_by_class_name('info') 
#    self.assertIn('successfully', messageBox.text) 
#     
#    # Check that staff status changed 
#    staffIcon = self.browser.find_element_by_xpath('//table[@id="result_list"]/tbody/tr[' + str(rowCount) + ']/td[5]/img') 
#    isStaff = staffIcon.get_attribute('alt') 
#    self.assertTrue(isStaff) 
#    print 'should now be staff' 
#   rowCount += 1 


    def test_admin_can_change_a_class_obj_bank_id(self): 
     """ 
     Admin users can change a class's objective bank id 
     """ 
     self.fail('Finish writing the test!') 

    def test_logging_out_redirects_to_login_page(self): 
     """ 
     Logging out of the admin page should redirect to the main page 
     """ 
     self.admin_log_in_complete() 
     logOut = self.browser.find_element_by_link_text('Log out') 
     logOut.click() 
     body = self.browser.find_element_by_tag_name('body') 
     self.assertIn('VCB Administration', body.text) 
+0

I предположил бы, потому что он пытается сохранить FK, которого не существует. Вероятно, вы хотите заполнить тестовый db приборами. –

+0

Извините, не могли бы вы быть более конкретными? Я изучаю его больше сейчас, но похоже, что он должен быть таким же, как предварительная заполнение базы данных, что я делаю в своем setUp(). Я бы подумал, что существуют FK, поскольку пользователь уже существует? -Благодаря! – user

+0

показать нам свой код. –

ответ

17

Как я уже говорил в комментариях, это похоже, является документированной ошибкой в ​​Django. Here и here являются официальными сообщениями об ошибках. Как сообщалось во второй ссылке, один обходной путь, чтобы поменять порядок django.contrib.auth и django.contrib.contenttypes в INSTALLED_APPS, как таковой:

Что первоначально это:

INSTALLED_APPS = (
    'django.contrib.auth', 
    'django.contrib.contenttypes', 
    'django.contrib.sessions', 
    'django.contrib.sites', 
    'django.contrib.admin', 
    'testapp' 
) 

должны стать:

INSTALLED_APPS = (
    'django.contrib.contenttypes', 
    'django.contrib.auth', 
    'django.contrib.sessions', 
    'django.contrib.sites', 
    'django.contrib.admin', 
    'testapp' 
) 
+0

Работал для меня, спасибо! Кстати, у меня была проблема с django 1.6.1. –

+2

Проблема все еще присутствует в Django 1.10. Это исправление по-прежнему работает. –

+1

Проблема все еще присутствует в Django 1.11.1. Это исправление по-прежнему работает. Спасибо –

Смежные вопросы