লেনদেন ব্যবস্থাপনার ত্রুটি "সংকেতগুলি ব্যবহার করার সময় আপনি 'পারমাণবিক' ব্লকটি শেষ না হওয়া অবধি অনুসন্ধানগুলি চালাতে পারবেন না, তবে কেবল ইউনিট পরীক্ষার সময়


194

জ্যাঙ্গো ইউজার মডেল উদাহরণটি সংরক্ষণ করার চেষ্টা করার সময় এবং তার পোস্ট_সেভ সিগন্যালে আমি কিছু মডেল সংরক্ষণ করছি যা বিদেশী কী হিসাবে ব্যবহারকারীর রয়েছে।

সিগন্যাল ব্যবহার করার সময় প্রসঙ্গ এবং ত্রুটিটি এই প্রশ্নের সাথে খুব মিল d

যাইহোক, এই ক্ষেত্রে, ত্রুটি দেখা দেয় শুধুমাত্র যখন ইউনিট টেস্টিং

এটি ম্যানুয়াল টেস্টিংয়ে ভাল কাজ করে তবে ইউনিট পরীক্ষাগুলি ব্যর্থ হয়।

আমি কি অনুপস্থিত কিছু আছে?

কোড স্নিপেটগুলি এখানে:

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)

ট্রেসব্যাক:

======================================================================
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.

----------------------------------------------------------------------

দস্তাবেজগুলি থেকে: "অন্যদিকে, একটি টেস্টকেস কোনও পরীক্ষার পরে টেবিলগুলি ছাঁটাই করে না Instead পরিবর্তে এটি পরীক্ষার শেষে একটি ডাটাবেস লেনদেনে পরীক্ষার কোডটি আবদ্ধ করে Both () এবং লেনদেনের ফলে সৃষ্ট হতে পারে এমন অন্তর্নিহিতগুলি (অ্যাটমিক ()) একটি ন্যাপ অপারেশন দ্বারা প্রতিস্থাপিত হয় This এটি গ্যারান্টি দেয় যে পরীক্ষার শেষে রোলব্যাকটি তার প্রাথমিক অবস্থায় ডাটাবেসটিকে পুনরুদ্ধার করে। "
গৌরব তোশনিওয়াল

6
আমি আমার সমস্যা খুঁজে পেয়েছি। "ট্রাইটি: ... ইন্টিগ্রিটি এয়ারার ব্যতীত: ..." এর মতো একটি ইন্টিগ্রিটিএরর ব্যতিক্রম এখানে ছিল: ট্রাই-ব্লকের অভ্যন্তরে লেনদেন.ট্যাটমিকটি ব্যবহার করার জন্য আমাকে যা করতে হয়েছিল: "চেষ্টা করুন: ট্রানজেকশন.টমিক () সহ: .. ... ইন্টিগ্রিটিরিয়ার ছাড়া: ... "এখন সবকিছু ঠিকঠাক কাজ করে।
caio

docs.djangoproject.com/en/dev/topics/db/transferences এবং তারপরে অনুসন্ধান করুন "ব্লক ব্যতীত একটি চেষ্টা করে র‌্যাপিং পারমাণবিকতা সততা ত্রুটির প্রাকৃতিক পরিচালনা করার অনুমতি দেয়:"
ক্যামহার্ট

উত্তর:


236

আমি নিজেই এই একই সমস্যায় পড়েছি। জ্যাঙ্গোর নতুন সংস্করণগুলিতে কীভাবে লেনদেন পরিচালনা করা হয় এমন এক দ্বিচারের কারণে এটি ঘটেছে যা ইচ্ছাকৃতভাবে ব্যতিক্রম ঘটায়।

আমার একটি ইউনিটেস্ট ছিল যা পরীক্ষা করে নিশ্চিত করা যে কোনও অনন্য কলাম সীমাবদ্ধতা উদ্দেশ্যমূলকভাবে ইন্টিগ্রিটিএরর ব্যতিক্রমটি ট্রিগার করে প্রয়োগ করা হয়েছিল:

def test_constraint(self):
    try:
        # Duplicates should be prevented.
        models.Question.objects.create(domain=self.domain, slug='barks')
        self.fail('Duplicate question allowed.')
    except IntegrityError:
        pass

    do_more_model_stuff()

জাজানো ১.৪-এ, এটি দুর্দান্ত কাজ করে। তবে, জাজানো 1.5 / 1.6 এ, প্রতিটি পরীক্ষা একটি লেনদেনের মধ্যে আবৃত থাকে, সুতরাং যদি কোনও ব্যতিক্রম ঘটে থাকে, তবে আপনি স্পষ্টভাবে এটিকে পিছনে না ফেরা পর্যন্ত এটি লেনদেনটি ভেঙে দেয়। অতএব, সেই লেনদেনে আর কোনও ওআরএম ক্রিয়াকলাপ যেমন আমার আমার ব্যতিক্রমটি do_more_model_stuff()ব্যর্থ হবে django.db.transaction.TransactionManagementError

মন্তব্যে উল্লিখিত সিওওর মতো সমাধানটি আপনার ব্যতিক্রম ক্যাপচার করা transaction.atomic :

from django.db import transaction
def test_constraint(self):
    try:
        # Duplicates should be prevented.
        with transaction.atomic():
            models.Question.objects.create(domain=self.domain, slug='barks')
        self.fail('Duplicate question allowed.')
    except IntegrityError:
        pass

এটি উদ্দেশ্যমূলকভাবে ছুঁয়ে যাওয়া ব্যতিক্রমকে পুরো ইউনিটস্টেটের লেনদেন ভাঙা থেকে বিরত রাখবে।


70
এছাড়াও কেবল আপনার টেস্ট ক্লাসকে কেবল টেস্টকেস না করে ট্রানজেকশন টেস্টকেস হিসাবে ঘোষণা করার বিষয়টি বিবেচনা করুন।
mkoistinen

1
ওহ, আমি সম্পর্কিত প্রশ্নটি অন্য একটি প্রশ্ন থেকে পেয়েছি । নথিটি এখানে
ইয়াওবিন

2
আমার জন্য, আমার ইতিমধ্যে একটি transaction.atomic()ব্লক ছিল , তবে আমি এই ত্রুটিটি পেয়েছি এবং কেন তা আমার কোনও ধারণা নেই। আমি এই উত্তরের পরামর্শ নিয়েছি এবং সমস্যাটির আশেপাশে আমার পারমাণবিক ব্লকের ভিতরে নেস্টেড পারমাণবিক ব্লক রেখেছি। এর পরে, এটি আমার আঘাত করা সততা ত্রুটির একটি বিশদ ত্রুটি দিয়েছে, যা আমাকে আমার কোড ঠিক করতে এবং আমি যা করার চেষ্টা করছিলাম তা করার অনুমতি দেয়।
অ্যালানএসই

5
@ এমকোইস্টিনেন TestCaseউত্তরাধিকার সূত্রে প্রাপ্ত TransactionTestCaseতাই এটি পরিবর্তন করার দরকার নেই। আপনি যদি পরীক্ষার জন্য ডিবিতে পরিচালনা না করেন SimpleTestCase
বিএনএস

1
@ বিএনএস আপনি মন্তব্যটির পয়েন্ট মিস করছেন। হ্যাঁ TestCaseউত্তরাধিকার সূত্রে প্রাপ্ত TransactionTestCaseতবে এর আচরণটি একেবারেই আলাদা: এটি প্রতিটি পরীক্ষার পদ্ধতি লেনদেনে জড় করে। TransactionTestCaseঅন্যদিকে, সম্ভবত বিভ্রান্তিকরভাবে নামকরণ করা হয়েছে: এটি ডিবি পুনরায় সেট করার জন্য টেবিলগুলি ছাঁটাই করে - নামকরণটি মনে হয় যে আপনি কোনও পরীক্ষার মধ্যে লেনদেন পরীক্ষা করতে পারেন, পরীক্ষাটি লেনদেন হিসাবে মোড়ানো নয়!
সিএস

48

যেহেতু @ এমকোইস্টিনেন কখনই তার মন্তব্য করেননি , একটি উত্তর, আমি তার পরামর্শ পোস্ট করব যাতে লোকেরা মন্তব্যগুলির মাধ্যমে খনন করতে না পারে।

আপনার টেস্ট ক্লাসকে কেবলমাত্র টেস্টকেস না করে ট্রানজেকশন টেস্টকেস হিসাবে ঘোষণা করার বিষয়টি বিবেচনা করুন।

দস্তাবেজগুলি থেকে : একটি ট্রানজেকশন টেস্টকেস কমিট এবং রোলব্যাক কল করতে পারে এবং ডাটাবেসে এই কলগুলির প্রভাব পর্যবেক্ষণ করতে পারে।


2
এটির জন্য +1, তবে ডকস হিসাবে, "জ্যাঙ্গোর টেস্টকেস ক্লাস হ'ল লেনদেনের টেস্টক্যাসের সর্বাধিক ব্যবহৃত সাবক্লাস"। মূল প্রশ্নের উত্তর দেওয়ার জন্য, আমরা কি টেস্টকেসের পরিবর্তে সিম্পলটেষ্টকেস ব্যবহার করব না? সিম্পল টেস্টকেসে পারমাণবিক ডাটাবেস বৈশিষ্ট্য নেই।
ডাইগোরোকব

@daigorocub যখন থেকে উত্তরাধিকার সূত্রে প্রাপ্ত SimpleTestCase, allow_database_queries = Trueপরীক্ষার শ্রেণীর ভিতরের যোগ করা হবে যাতে এটি একটি থুতু নেই AssertionError("Database queries aren't allowed in SimpleTestCase...",)
ক্রিসটিফতি

এই উত্তরটি আমার পক্ষে সবচেয়ে ভাল কাজ করে যেহেতু আমি অখণ্ডতার জন্য পরীক্ষা করার চেষ্টা করছিলাম তখন উত্থাপিত হবে এবং তারপরে আমাকে আরও বেশি ডেটাবেস চালানো দরকার জিজ্ঞাসাগুলি সংরক্ষণ করুন
কিম স্ট্যাকস

8

ব্যবহার যদি pytest-জ্যাঙ্গো আপনি পাস করতে পারেন transaction=Trueথেকে django_dbএই ত্রুটি এড়াতে প্রসাধক।

দেখুন https://pytest-django.readthedocs.io/en/latest/database.html#testing-transactions

জ্যাঙ্গোতে নিজেই লেনদেনের টেস্টকেস রয়েছে যা আপনাকে লেনদেন পরীক্ষা করার অনুমতি দেয় এবং এগুলি পৃথক করার জন্য পরীক্ষার মধ্যে ডাটাবেস ফ্লাশ করে দেবে। এর নেতিবাচক দিকটি হ'ল ডাটাবেসগুলির প্রয়োজনীয় ফ্লাশিংয়ের কারণে এই পরীক্ষাগুলি সেট আপ করতে অনেক ধীর হয়। পাইস্ট-জ্যাঙ্গো এই স্টাইলের পরীক্ষাগুলিও সমর্থন করে, যা আপনি django_db চিহ্নটিতে একটি যুক্তি ব্যবহার করে নির্বাচন করতে পারেন:

@pytest.mark.django_db(transaction=True)
def test_spam():
    pass  # test relying on transactions

এই সমাধানটি নিয়ে আমার সমস্যা ছিল, আমার ডিবিতে প্রাথমিক তথ্য ছিল (মাইগ্রেশন দ্বারা যুক্ত)। এই সমাধানটি ডাটাবেসটিকে ফ্লাশ করে, তাই এই প্রাথমিক ডেটার উপর নির্ভরশীল অন্যান্য পরীক্ষাগুলি ব্যর্থ হতে শুরু করে।
আবুমালিক

1

আমার জন্য, প্রস্তাবিত ফিক্সগুলি কার্যকর হয়নি। আমার পরীক্ষাগুলিতে, আমি কিছু উপ-প্রক্রিয়াগুলি দিয়ে খুলিPopen বিশ্লেষণ / লিন্টের মাইগ্রেশনগুলি বিশ্লেষণের জন্য (উদাহরণস্বরূপ, কোনও মডেল পরিবর্তন না হলে একটি পরীক্ষার চেক)।

আমার জন্য, সাবক্লাসিংয়ের SimpleTestCaseপরিবর্তে TestCaseকৌশলটি করেছিলেন।

নোট যে SimpleTestCaseডাটাবেস ব্যবহার করতে অনুমতি দেয় না।

যদিও এটি মূল প্রশ্নের উত্তর দেয় না, আমি আশা করি এটি যাইহোক কিছু লোককে সহায়তা করে।


1

এই প্রশ্নের উত্তরের ভিত্তিতে এটি করার আরও একটি উপায় এখানে রয়েছে:

with transaction.atomic():
    self.assertRaises(IntegrityError, models.Question.objects.create, **{'domain':self.domain, 'slug':'barks'})

0

আমি আমার ক্রিয়েট_টেষ্ট_ডাটা ফাংশনটিতে জাঙ্গো ১.৯. using ব্যবহার করে ইউনিট পরীক্ষা চালানোর ক্ষেত্রে এই ত্রুটিটি পেয়েছি। এটি জ্যাঙ্গোর আগের সংস্করণগুলিতে কাজ করেছিল।

দেখে মনে হচ্ছে:

cls.localauth,_ = Organisation.objects.get_or_create(organisation_type=cls.orgtypeLA, name='LA for test', email_general='test@test.com', address='test', postcode='test', telephone='test')
cls.chamber,_ = Organisation.objects.get_or_create(organisation_type=cls.orgtypeC, name='chamber for test', email_general='test@test.com', address='test', postcode='test', telephone='test')
cls.lawfirm,_ = Organisation.objects.get_or_create(organisation_type=cls.orgtypeL, name='lawfirm for test', email_general='test@test.com', address='test', postcode='test', telephone='test')

cls.chamber.active = True
cls.chamber.save()

cls.localauth.active = True
cls.localauth.save()    <---- error here

cls.lawfirm.active = True
cls.lawfirm.save()

পরিবর্তে আমার সমাধানটি আপডেট_আর_ক্রিয়েট ব্যবহার করা ছিল:

cls.localauth,_ = Organisation.objects.update_or_create(organisation_type=cls.orgtypeLA, name='LA for test', email_general='test@test.com', address='test', postcode='test', telephone='test', defaults={'active': True})
cls.chamber,_ = Organisation.objects.update_or_create(organisation_type=cls.orgtypeC, name='chamber for test', email_general='test@test.com', address='test', postcode='test', telephone='test', defaults={'active': True})
cls.lawfirm,_ = Organisation.objects.update_or_create(organisation_type=cls.orgtypeL, name='lawfirm for test', email_general='test@test.com', address='test', postcode='test', telephone='test', defaults={'active': True})

1
get_or_create()পাশাপাশি কাজ করে, দেখে মনে হয় এটি সংরক্ষণ করুন () এটি কোনও লেনদেনের মতো করে না at
টিমোথি মাকোবু

0

আমি একই সমস্যা আছে, কিন্তু with transaction.atomic()এবং TransactionTestCaseআমার জন্য কাজ করে নি।

python manage.py test -r পরিবর্তে python manage.py test আমার জন্য ঠিক আছে, সম্ভবত মৃত্যুদন্ডের ক্রম অত্যন্ত গুরুত্বপূর্ণ

তারপরে আমি অর্ডার সম্পর্কে একটি ডক পাই যা পরীক্ষাগুলি কার্যকর করা হয় , এতে উল্লেখ করা হয় যে কোন পরীক্ষাটি প্রথম চলবে।

সুতরাং, আমি unittest.TestCaseঅন্যান্য সাধারণ পরীক্ষার জন্য ডাটাবেস ইন্টারঅ্যাকশনের জন্য টেস্টকেস ব্যবহার করি , এটি এখন কাজ করে!


0

@Kdazzle এর উত্তরটি সঠিক। আমি এটি চেষ্টা করিনি কারণ লোকেরা বলেছিল যে 'জ্যাঙ্গোর টেস্টকেস ক্লাসটি ট্রানজেকশন টেস্টকেসের একটি বেশি ব্যবহৃত সাবক্লাস' তাই আমি ভেবেছিলাম এটি এক বা অন্যরকম একই ব্যবহার। তবে জাহাঙ্গীর রাহমনভের ব্লগ এটি আরও ভালভাবে ব্যাখ্যা করেছে:

টেস্টকেস ক্লাস দুটি নেস্টেড পারমাণবিক () ব্লকের মধ্যে পরীক্ষাগুলি মোড়ানো: পুরো ক্লাসের জন্য একটি এবং প্রতিটি পরীক্ষার জন্য একটি করে। এখানেই ট্রানজেকশন টেস্টকেস ব্যবহার করা উচিত। এটি পরমাণু () ব্লক দিয়ে পরীক্ষাগুলিকে মোড়া করে না এবং এইভাবে আপনি আপনার বিশেষ পদ্ধতিগুলি পরীক্ষা করতে পারেন যা কোনও সমস্যা ছাড়াই কোনও লেনদেনের প্রয়োজন require

সম্পাদনা: এটি কাজ করে না, আমি ভেবেছিলাম হ্যাঁ, তবে নেই।

4 বছরে তারা এটিকে স্থির করতে পারে .......................................


0
def test_wrong_user_country_db_constraint(self):
        """
        Check whether or not DB constraint doesnt allow to save wrong country code in DB.
        """
        self.test_user_data['user_country'] = 'XX'
        expected_constraint_name = "country_code_within_list_of_countries_check"

        with transaction.atomic():
            with self.assertRaisesRegex(IntegrityError, expected_constraint_name) as cm:
                get_user_model().objects.create_user(**self.test_user_data)

        self.assertFalse(
            get_user_model().objects.filter(email=self.test_user_data['email']).exists()
        )
with transaction.atomic() seems do the job correct

-4

আমারো একই ইস্যু ছিল.

আমার ক্ষেত্রে আমি এটি করছিলাম

author.tasks.add(tasks)

সুতরাং এটি রূপান্তর

author.tasks.add(*tasks)

সেই ত্রুটিটি সরানো হয়েছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.