Saya mendapatkan TransactionManagementError ketika mencoba untuk menyimpan contoh model Pengguna Django dan dalam sinyal post_save, saya menyimpan beberapa model yang memiliki pengguna sebagai kunci asing.
Konteks dan kesalahannya cukup mirip dengan pertanyaan ini django TransactionManagementError saat menggunakan sinyal
Namun, dalam kasus ini, kesalahan hanya terjadi saat pengujian unit .
Ini bekerja dengan baik dalam pengujian manual, tetapi pengujian unit gagal.
Apakah ada sesuatu yang saya lewatkan?
Berikut cuplikan kode:
views.py
@csrf_exempt
def mobileRegister(request):
if request.method == 'GET':
response = {"error": "GET request not accepted!!"}
return HttpResponse(json.dumps(response), content_type="application/json",status=500)
elif request.method == 'POST':
postdata = json.loads(request.body)
try:
# Get POST data which is to be used to save the user
username = postdata.get('phone')
password = postdata.get('password')
email = postdata.get('email',"")
first_name = postdata.get('first_name',"")
last_name = postdata.get('last_name',"")
user = User(username=username, email=email,
first_name=first_name, last_name=last_name)
user._company = postdata.get('company',None)
user._country_code = postdata.get('country_code',"+91")
user.is_verified=True
user._gcm_reg_id = postdata.get('reg_id',None)
user._gcm_device_id = postdata.get('device_id',None)
# Set Password for the user
user.set_password(password)
# Save the user
user.save()
signal.py
def create_user_profile(sender, instance, created, **kwargs):
if created:
company = None
companycontact = None
try: # Try to make userprofile with company and country code provided
user = User.objects.get(id=instance.id)
rand_pass = random.randint(1000, 9999)
company = Company.objects.get_or_create(name=instance._company,user=user)
companycontact = CompanyContact.objects.get_or_create(contact_type="Owner",company=company,contact_number=instance.username)
profile = UserProfile.objects.get_or_create(user=instance,phone=instance.username,verification_code=rand_pass,company=company,country_code=instance._country_code)
gcmDevice = GCMDevice.objects.create(registration_id=instance._gcm_reg_id,device_id=instance._gcm_reg_id,user=instance)
except Exception, e:
pass
tests.py
class AuthTestCase(TestCase):
fixtures = ['nextgencatalogs/fixtures.json']
def setUp(self):
self.user_data={
"phone":"0000000000",
"password":"123",
"first_name":"Gaurav",
"last_name":"Toshniwal"
}
def test_registration_api_get(self):
response = self.client.get("/mobileRegister/")
self.assertEqual(response.status_code,500)
def test_registration_api_post(self):
response = self.client.post(path="/mobileRegister/",
data=json.dumps(self.user_data),
content_type="application/json")
self.assertEqual(response.status_code,201)
self.user_data['username']=self.user_data['phone']
user = User.objects.get(username=self.user_data['username'])
# Check if the company was created
company = Company.objects.get(user__username=self.user_data['phone'])
self.assertIsInstance(company,Company)
# Check if the owner's contact is the same as the user's phone number
company_contact = CompanyContact.objects.get(company=company,contact_type="owner")
self.assertEqual(user.username,company_contact[0].contact_number)
Melacak kembali:
======================================================================
ERROR: test_registration_api_post (nextgencatalogs.apps.catalogsapp.tests.AuthTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/nextgencatalogs/apps/catalogsapp/tests.py", line 29, in test_registration_api_post
user = User.objects.get(username=self.user_data['username'])
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/manager.py", line 151, in get
return self.get_queryset().get(*args, **kwargs)
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/query.py", line 301, in get
num = len(clone)
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/query.py", line 77, in __len__
self._fetch_all()
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/query.py", line 854, in _fetch_all
self._result_cache = list(self.iterator())
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/query.py", line 220, in iterator
for row in compiler.results_iter():
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 710, in results_iter
for rows in self.execute_sql(MULTI):
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 781, in execute_sql
cursor.execute(sql, params)
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/backends/util.py", line 47, in execute
self.db.validate_no_broken_transaction()
File "/Users/gauravtoshniwal1989/Developer/Web/Server/ngc/ngcvenv/lib/python2.7/site-packages/django/db/backends/__init__.py", line 365, 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.
----------------------------------------------------------------------
python
django
unit-testing
django-signals
Gaurav Toshniwal
sumber
sumber
Jawaban:
Saya mengalami masalah yang sama sendiri. Hal ini disebabkan oleh kekhasan dalam bagaimana transaksi ditangani dalam versi baru Django ditambah dengan unittest yang dengan sengaja memicu pengecualian.
Saya memiliki unittest yang memeriksa untuk memastikan kendala kolom unik ditegakkan dengan sengaja memicu pengecualian IntegrityError:
Di Django 1.4, ini berfungsi dengan baik. Namun, dalam Django 1.5 / 1.6, setiap tes dibungkus dalam suatu transaksi, jadi jika pengecualian terjadi, itu akan memecah transaksi sampai Anda secara eksplisit mengembalikannya. Karenanya, setiap operasi ORM lebih lanjut dalam transaksi itu, seperti saya
do_more_model_stuff()
, akan gagal dengandjango.db.transaction.TransactionManagementError
pengecualian itu.Seperti caio yang disebutkan dalam komentar, solusinya adalah menangkap pengecualian Anda dengan
transaction.atomic
seperti:Itu akan mencegah pengecualian yang sengaja dilempar dari melanggar seluruh transaksi unittest.
sumber
transaction.atomic()
blok, tetapi saya mendapatkan kesalahan ini dan saya tidak tahu mengapa. Saya mengambil saran jawaban ini dan meletakkan blok atom bersarang di dalam blok atom saya di sekitar area masalah. Setelah itu, ia memberikan kesalahan rinci kesalahan integritas yang saya tekan, memungkinkan saya untuk memperbaiki kode saya dan melakukan apa yang saya coba lakukan.TestCase
mewarisi dariTransactionTestCase
jadi tidak perlu mengubahnya. Jika Anda tidak beroperasi pada DB dalam penggunaan tesSimpleTestCase
.TestCase
mewarisi dariTransactionTestCase
tetapi perilakunya sangat berbeda: ia membungkus setiap metode pengujian dalam suatu transaksi.TransactionTestCase
, di sisi lain, mungkin diberi nama yang menyesatkan: ini memotong tabel untuk mereset db - penamaan tersebut tampaknya mencerminkan bahwa Anda dapat menguji transaksi dalam suatu tes, bukan bahwa tes tersebut dibungkus sebagai suatu transaksi!Karena @mkoistinen tidak pernah membuat komentar , jawaban, saya akan mengirim sarannya sehingga orang tidak perlu menggali komentar.
Dari dokumen : TransactionTestCase dapat memanggil commit dan rollback dan mengamati efek dari panggilan ini pada database.
sumber
SimpleTestCase
,allow_database_queries = True
harus ditambahkan di dalam kelas tes, agar tidak dimuntahkanAssertionError("Database queries aren't allowed in SimpleTestCase...",)
.Jika menggunakan pytest-django Anda dapat beralih
transaction=True
kedjango_db
dekorator untuk menghindari kesalahan ini.Lihat https://pytest-django.readthedocs.io/en/latest/database.html#testing-transactions
sumber
Bagi saya, perbaikan yang diusulkan tidak berhasil. Dalam pengujian saya, saya membuka beberapa subproses dengan
Popen
untuk menganalisis / lint migrasi (mis. Satu tes memeriksa jika tidak ada perubahan model).Bagi saya, subclassing dari
SimpleTestCase
bukannyaTestCase
memang berhasil.Catatan yang
SimpleTestCase
tidak memungkinkan untuk menggunakan database.Meskipun ini tidak menjawab pertanyaan awal, saya harap ini membantu beberapa orang.
sumber
Berikut ini cara lain untuk melakukannya, berdasarkan jawaban atas pertanyaan ini:
sumber
Saya mendapatkan kesalahan ini saat menjalankan tes unit di fungsi create_test_data menggunakan django 1.9.7. Ini bekerja di versi django sebelumnya.
Itu terlihat seperti ini:
Solusi saya adalah menggunakan pembaruan_or_create sebagai gantinya:
sumber
get_or_create()
berfungsi juga, tampaknya itu .save () tidak seperti di dalam fungsi transaksi.atomic () dihiasi (saya gagal hanya dengan 1 panggilan di sana).Saya memiliki masalah yang sama, tetapi
with transaction.atomic()
danTransactionTestCase
tidak bekerja untuk saya.python manage.py test -r
bukannyapython manage.py test
ok untuk saya, mungkin urutan eksekusi sangat pentingkemudian saya menemukan dokumen tentang Urutan di mana tes dijalankan , Ini menyebutkan tes mana yang akan dijalankan pertama.
Jadi, saya menggunakan TestCase untuk interaksi basis data,
unittest.TestCase
untuk tes sederhana lainnya, berfungsi sekarang!sumber
Jawaban @kdazzle benar. Saya tidak mencobanya karena orang mengatakan bahwa 'kelas TestCase Django adalah subkelas TransactionTestCase' yang lebih umum digunakan, jadi saya pikir itu adalah penggunaan yang sama satu atau yang lain. Tetapi blog Jahongir Rahmonov menjelaskannya dengan lebih baik:
EDIT: Tidak berhasil, saya pikir ya, tapi TIDAK.
Dalam 4 tahun mereka dapat memperbaiki ini .......................................
sumber
sumber
Saya memiliki masalah yang sama.
Dalam Kasus Saya, saya melakukan ini
jadi mengubahnya menjadi
Menghapus kesalahan itu.
sumber