从 Django 1.5 升级到 1.7 后测试出现异常
exception in tests after upgrading from django 1.5 to 1.7
这是失败的测试:
def test_registering_user_twice_cause_error_msg(self):
user=User(name='pyRock',email='python@rocks.com')
user.save()
#create the request used to test the view
self.request.session = {}
self.request.method = 'POST'
self.request.POST = {
'email':'python@rocks.com',
'name':'pyRock',
'stripe_token':'...',
'last_4_digits':'4242',
'password':'bad_password',
'ver_password':'bad_password'
}
expected_form=UserForm(self.request.POST)
expected_form.is_valid()
expected_form.addError('python@rocks.com is already a member')
#create the expected html
html = render_to_response(
'register.html',
{
'form': expected_form,
'months': range(1, 12),
'publishable': settings.STRIPE_PUBLISHABLE,
'soon': soon(),
'user': None,
'years': list(range(2011, 2036)),
}
)
#mock out stripe so we don't hit their server
with mock.patch('stripe.Customer') as stripe_mock:
config = {'create.return_value': mock.Mock()}
stripe_mock.configure_mock(**config)
#run the test
resp = register(self.request)
#verify that we did things correctly
self.assertEqual(resp.status_code, 200)
self.assertEqual(self.request.session, {})
self.assertEqual(resp.content, html.content)
#assert there is no records in the database.
users = User.objects.filter(email="python@rocks.com")
self.assertEqual(len(users), 1)
所以当 运行 测试时它会抛出以下内容:
ERROR: test_registering_user_twice_cause_error_msg (payments.tests.RegisterPageTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/1111/_realpython/d3/django_ecommerce/payments/tests.py", line 278, in test_registering_user_twice_cause_error_msg
self.assertEqual(len(users), 1)
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/query.py", line 122, in __len__
self._fetch_all()
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/query.py", line 966, in _fetch_all
self._result_cache = list(self.iterator())
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/query.py", line 265, in iterator
for row in compiler.results_iter():
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 700, in results_iter
for rows in self.execute_sql(MULTI):
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 786, in execute_sql
cursor.execute(sql, params)
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/backends/utils.py", line 59, in execute
self.db.validate_no_broken_transaction()
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/backends/__init__.py", line 386, in validate_no_broken_transaction
"An error occurred in the current transaction. You can't "
TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
我阅读了一些关于 Django 将每个测试包装在一个事务中的答案,但由于我是 Django 菜鸟,我无法从中得到任何东西,上面的代码是教程。
更有趣的是异常发生在断言中。如果我删除它,即使存在查询 users = User.objects.filter(email="python@rocks.com")
,测试也会通过。但是,如果我以某种方式引用 users
,只说 print users
测试再次中断。
所以这是怎么回事?
谢谢!
So what's going on?
如前所述,this is a duplicate。
但我将单独说明它在您访问 users
时中断的原因。发生这种情况的原因是 Django 数据库调用是惰性的,会延迟执行直到您最终使用查询。
因此,如果您从不使用或迭代 users
,它将为您节省一次数据库调用。这就是为什么它看起来像工作的原因,因为如果你删除 len(users)
它永远不需要 users
的结果,所以不会查询它。
这是失败的测试:
def test_registering_user_twice_cause_error_msg(self):
user=User(name='pyRock',email='python@rocks.com')
user.save()
#create the request used to test the view
self.request.session = {}
self.request.method = 'POST'
self.request.POST = {
'email':'python@rocks.com',
'name':'pyRock',
'stripe_token':'...',
'last_4_digits':'4242',
'password':'bad_password',
'ver_password':'bad_password'
}
expected_form=UserForm(self.request.POST)
expected_form.is_valid()
expected_form.addError('python@rocks.com is already a member')
#create the expected html
html = render_to_response(
'register.html',
{
'form': expected_form,
'months': range(1, 12),
'publishable': settings.STRIPE_PUBLISHABLE,
'soon': soon(),
'user': None,
'years': list(range(2011, 2036)),
}
)
#mock out stripe so we don't hit their server
with mock.patch('stripe.Customer') as stripe_mock:
config = {'create.return_value': mock.Mock()}
stripe_mock.configure_mock(**config)
#run the test
resp = register(self.request)
#verify that we did things correctly
self.assertEqual(resp.status_code, 200)
self.assertEqual(self.request.session, {})
self.assertEqual(resp.content, html.content)
#assert there is no records in the database.
users = User.objects.filter(email="python@rocks.com")
self.assertEqual(len(users), 1)
所以当 运行 测试时它会抛出以下内容:
ERROR: test_registering_user_twice_cause_error_msg (payments.tests.RegisterPageTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/1111/_realpython/d3/django_ecommerce/payments/tests.py", line 278, in test_registering_user_twice_cause_error_msg
self.assertEqual(len(users), 1)
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/query.py", line 122, in __len__
self._fetch_all()
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/query.py", line 966, in _fetch_all
self._result_cache = list(self.iterator())
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/query.py", line 265, in iterator
for row in compiler.results_iter():
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 700, in results_iter
for rows in self.execute_sql(MULTI):
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 786, in execute_sql
cursor.execute(sql, params)
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/backends/utils.py", line 59, in execute
self.db.validate_no_broken_transaction()
File "/Users/1111/.virtualenvs/d317/lib/python2.7/site-packages/django/db/backends/__init__.py", line 386, in validate_no_broken_transaction
"An error occurred in the current transaction. You can't "
TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
我阅读了一些关于 Django 将每个测试包装在一个事务中的答案,但由于我是 Django 菜鸟,我无法从中得到任何东西,上面的代码是教程。
更有趣的是异常发生在断言中。如果我删除它,即使存在查询 users = User.objects.filter(email="python@rocks.com")
,测试也会通过。但是,如果我以某种方式引用 users
,只说 print users
测试再次中断。
所以这是怎么回事?
谢谢!
So what's going on?
如前所述,this is a duplicate。
但我将单独说明它在您访问 users
时中断的原因。发生这种情况的原因是 Django 数据库调用是惰性的,会延迟执行直到您最终使用查询。
因此,如果您从不使用或迭代 users
,它将为您节省一次数据库调用。这就是为什么它看起来像工作的原因,因为如果你删除 len(users)
它永远不需要 users
的结果,所以不会查询它。