ปิดใช้งานการย้ายข้อมูลเมื่อรันการทดสอบหน่วยใน Django 1.7


110

Django 1.7แนะนำการโยกย้ายฐานข้อมูล

เมื่อเรียกใช้การทดสอบหน่วยใน Django 1.7 จะบังคับให้มีการโยกย้ายซึ่งใช้เวลานาน ดังนั้นฉันต้องการข้ามการย้าย django และสร้างฐานข้อมูลในสถานะสุดท้าย

ฉันรู้ว่าการเพิกเฉยต่อการย้ายข้อมูลอาจเป็นแนวทางปฏิบัติที่ไม่ดีเนื่องจากส่วนนั้นจะไม่มีการทดสอบโค้ด แต่นั่นไม่ใช่กรณี: ฉันกำลังเรียกใช้การย้ายข้อมูลทั้งหมดในเซิร์ฟเวอร์ทดสอบ CI (เจนกินส์) ฉันต้องการข้ามการย้ายข้อมูลในการทดสอบในพื้นที่เท่านั้นซึ่งความเร็วมีความสำคัญ


บริบทบางส่วน:

จนถึง Django 1.6เมื่อใช้ South ฉันใช้การตั้งค่าSOUTH_TESTS_MIGRATE :

ตามค่าเริ่มต้นคำสั่ง syncdb ของ South จะใช้การย้ายข้อมูลด้วยหากทำงานในโหมดไม่โต้ตอบซึ่งรวมถึงเวลาที่คุณกำลังทำการทดสอบคำสั่งจะเรียกใช้การย้ายข้อมูลทุกครั้งที่คุณเรียกใช้การทดสอบ

หากคุณต้องการให้นักวิ่งทดสอบใช้ syncdb แทนการโอนย้ายตัวอย่างเช่นหากการย้ายข้อมูลของคุณใช้เวลานานเกินไปในการใช้งานให้ตั้งค่า SOUTH_TESTS_MIGRATE = False ใน settings.py

อย่างไรก็ตามSyncDBไม่อยู่อีกต่อไปตอนนี้ก็โยกย้าย

และจาก Django 1.8ฉันจะใช้พารามิเตอร์--keepdb :

ตัวเลือก --keepdb สามารถใช้เพื่อรักษาฐานข้อมูลการทดสอบระหว่างการทดสอบ สิ่งนี้มีข้อดีของการข้ามทั้งการดำเนินการสร้างและทำลายซึ่งช่วยลดเวลาในการเรียกใช้การทดสอบได้มากโดยเฉพาะอย่างยิ่งการทดสอบในชุดทดสอบขนาดใหญ่ หากไม่มีฐานข้อมูลทดสอบฐานข้อมูลจะถูกสร้างขึ้นในการรันครั้งแรกจากนั้นจะคงไว้สำหรับการรันครั้งต่อ ๆ ไป การย้ายข้อมูลที่ไม่ได้ใช้จะถูกนำไปใช้กับฐานข้อมูลทดสอบก่อนที่จะเรียกใช้ชุดทดสอบ

ดังนั้นคำถามนี้ จำกัด ไว้ที่ Django 1.7


ฉันขอยืนยันว่าในระหว่าง UT คุณไม่ได้เรียกใช้การย้ายข้อมูลด้วยวิธีที่ทดสอบเนื่องจาก DB ที่คุณเริ่มต้นนั้นไม่มีอยู่จริง การทดสอบการย้ายข้อมูลจะเกิดขึ้นเมื่อคุณกำลังย้ายฐานข้อมูลที่มีอยู่เท่านั้น ธุรกิจการโยกย้าย 1.7 นี้เป็นเสี้ยนที่แท้จริงครั้งแรกที่ฉันเคยมีกับ Django แต่มันเป็นเรื่องที่น่ารำคาญมาก อย่างน้อยทางใต้ก็มีสถานการณ์การทดสอบที่เหมาะสมสำหรับการย้ายข้อมูล
boatcoder

django-test-without-migrationsแพคเกจได้รับประโยชน์จริงๆสำหรับฉันคุณอาจต้องการที่จะเปลี่ยนคำตอบที่ได้รับการยอมรับที่จะstackoverflow.com/a/28993456/200224
แอนดี้

ฉันชอบหลีกเลี่ยงการเพิ่มการอ้างอิงใหม่ถ้าเป็นไปได้
David Arcos

คำตอบ:


79

ดูวิธีแก้ปัญหานี้โพสต์โดย Bernie Sumption ไปยังรายชื่อผู้รับจดหมายของนักพัฒนา Django:

หากยังไม่ได้เรียกใช้ makemigrations คำสั่ง "migrate" จะถือว่าแอปไม่ได้ย้ายข้อมูลและสร้างตารางโดยตรงจากโมเดลเช่นเดียวกับที่ syncdb ใน 1.6 ฉันกำหนดโมดูลการตั้งค่าใหม่สำหรับการทดสอบหน่วยที่เรียกว่า "settings_test.py" ซึ่งนำเข้า * จากโมดูลการตั้งค่าหลักและเพิ่มบรรทัดนี้:

MIGRATION_MODULES = {"myapp": "myapp.migrations_not_used_in_tests"}

จากนั้นฉันจะทำการทดสอบดังนี้:

DJANGO_SETTINGS_MODULE = "myapp.settings_test" การทดสอบ python Manage.py

คนโง่คนนี้ย้ายไปโดยคิดว่าแอปไม่ได้รับการโยกย้ายดังนั้นทุกครั้งที่สร้างฐานข้อมูลทดสอบจะสะท้อนถึงโครงสร้างปัจจุบันของ models.py

ใน Django 1.9 สถานการณ์นี้จะดีขึ้นบ้างและคุณสามารถตั้งค่าเป็นNone:

MIGRATION_MODULES = {"myapp": ไม่มี}


9
โปรดทราบว่าmyapp.migrations_not_used_in_testsโมดูลไม่ควรมีอยู่
bmihelac

4
นอกเหนือจากความคิดเห็นที่ @bmihelac เกี่ยวกับโมดูลที่ไม่มีอยู่แล้วสตริงโมดูลต้องมีสตริงย่อย 'การย้ายข้อมูล' ด้วยเหตุใดโปรดดู: github.com/django/django/blob/stable/1.7.x/django/db/migrations / …
nealtodd

7
ส่วนสำคัญของฟังก์ชันสำหรับการสร้าง MIGRATION_MODULES แบบไดนามิกใน settings_test.py: gist.github.com/nealtodd/2869341f38f5b1eeb86d
nealtodd

1
TY. ฉันสามารถลดการทดสอบหน่วยจาก 13 วินาทีเหลือ 4 วินาทีด้วยเหตุนี้ นอกจากนี้ยังสามารถหาความเร็วที่เพิ่มขึ้นได้โดยใช้ sqlite ในการทดสอบ สำหรับฉันการใช้ postgres ในการทดสอบใช้เวลา 5.5 วินาที แต่ sqlite ใช้เวลา 4 วินาที
Gattster

21
จากความคิดเห็นของส่วนสำคัญของ @nealtodd นี่คือลิงค์ไปยังวิธีแก้ปัญหาที่หลีกเลี่ยงข้อผิดพลาดบางอย่างและง่ายมาก: gist.github.com/NotSqrt/5f3c76cd15e40ef62d09
djsutho

72

นี่คือจุดสิ้นสุดของไฟล์การตั้งค่าของฉัน:

class DisableMigrations(object):

    def __contains__(self, item):
        return True

    def __getitem__(self, item):
        return None


TESTS_IN_PROGRESS = False
if 'test' in sys.argv[1:] or 'jenkins' in sys.argv[1:]:
    logging.disable(logging.CRITICAL)
    PASSWORD_HASHERS = (
        'django.contrib.auth.hashers.MD5PasswordHasher',
    )
    DEBUG = False
    TEMPLATE_DEBUG = False
    TESTS_IN_PROGRESS = True
    MIGRATION_MODULES = DisableMigrations()

ตามตัวอย่างข้อมูลนี้

ฉันปิดใช้งานการย้ายข้อมูลเมื่อกำลังดำเนินการทดสอบเท่านั้น


1
ดี! ฉันจะเพิ่ม__setitem__(self, *_)วิธีการเช่นกันเพราะเรามีปัญหากับแอพที่ตั้งค่าการโยกย้ายของตัวเองเช่น settings.MIGRATION_MODULES['chroniker'] = 'db_migrations'
Zhe Li

1
ขอบคุณมากสำหรับสิ่งนี้เป็นสิ่งเดียวที่ฉันพบว่าใช้งานได้จริง
ปุย

สิ่งนี้ใช้ไม่ได้ใน Django 1.9 อีกต่อไปเมื่อเรียกใช้การทดสอบในโหมดคู่ขนาน การใช้การทดสอบแบบไม่ขนานแบบปกติจะยังคงทำงานได้ดี แต่การเปลี่ยนไปใช้โหมดคู่ขนานทำให้เกิดข้อผิดพลาดที่ไม่พบตาราง
LS55321

@LeeSemel ในโหมดขนานคุณอาจต้องการใช้วิธีแก้ปัญหาจาก rlmv
Guillaume Vincent

@guillaumevincent ฉันมีปัญหาเดียวกันเมื่อใช้ django-test-without-migrations ในโหมดขนาน
LS55321


3

อัปเดต : ไม่เป็นไรการเปลี่ยนแปลงนี้ถูกเปลี่ยนกลับก่อนที่จะเผยแพร่ 1.10 ขั้นสุดท้าย หวังว่ามันจะกลับมาในเวอร์ชันอนาคต


โปรดทราบว่าใน Django 1.10 สิ่งนี้สามารถควบคุมได้โดยการตั้งค่าฐานข้อมูลทดสอบ

โยกย้าย

ค่าเริ่มต้น: True

หากตั้งค่าเป็นFalseDjango จะไม่ใช้การย้ายข้อมูลเพื่อสร้างฐานข้อมูลทดสอบ


2

https://gist.github.com/apollovy/22826f493ad2d06d9a9a22464730ce0b

MIGRATION_MODULES = {
    app[app.rfind('.') + 1:]: 'my_app.migrations_not_used_in_tests'
    for app in INSTALLED_APPS
}

ยินดีต้อนรับสู่ stackoverflow โปรดดูได้ที่การท่องเที่ยวและศูนย์ช่วยเหลือ โดยทั่วไปแล้วไม่ควรให้คำตอบเพียงบรรทัดเดียว แต่ยังอธิบายว่าทำไม (คุณคิดว่า) คำตอบของคุณถูกต้อง
Burki

1

สำหรับ django 1.9 ขึ้นไปคำตอบของ Guillaume Vincent ใช้ไม่ได้อีกต่อไปดังนั้นนี่คือทางออกใหม่:

ฉันใช้ตัวอย่างข้อมูลนี้ในไฟล์การตั้งค่าของฉันตามคำจำกัดความของไฟล์ INSTALLED_APPS

if os.environ.get('TESTS_WITHOUT_MIGRATIONS', False):
    MIGRATION_MODULES = {
        app.split('.')[-1]: None for app in INSTALLED_APPS
    }

มันจะวนซ้ำบนแอพที่ติดตั้งทั้งหมดและทำเครื่องหมายว่าแต่ละแอพไม่มีโมดูลการโอนย้าย ดูเอกสาร Django สำหรับข้อมูลเพิ่มเติม

การใช้ตัวอย่างข้อมูลนี้คุณสามารถเรียกใช้การทดสอบการตั้งค่าตัวแปรสภาพแวดล้อมTESTS_WITHOUT_MIGRATIONSเช่น:

TESTS_WITHOUT_MIGRATIONS=1 ./manage.py test

1

ฉันเพิ่งรู้วิธีปิดการใช้งานการย้ายข้อมูลหลังจาก django 1.10 อาจช่วยได้สำหรับใครบางคน นี่คือลิงค์ที่ git

class DisableMigrations(dict):
    def __contains__(self, item):
        return True

    def __getitem__(self, item):
        return None

DATABASES = DisableMigrations()

MIGRATION_MODULES = DisableMigrations()

การย้ายข้อมูลสำหรับ django 1.10 มีสองส่วนโปรดดูที่load_diskและrecorder

ส่วนของload_diskรูปแบบการย้ายข้อมูลของแอปที่เพิ่มเข้ามาINSTALL_APP และส่วนของrecorderสำหรับการเชื่อมต่อฐานข้อมูลสำหรับเวอร์ชันก่อน 1.9 เราจำเป็นต้องตั้งค่าMIGRATION_MODULES={'do.not.migrate':'notmigrations'}เมื่อคุณกำลังทำการทดสอบตอนนี้เราจำเป็นต้องตั้งค่าเป็นไม่มีเช่นนั้นMIGRATION_MODULES={'do.not.migrate':None} ดังนั้นหากเราไม่ต้องการทำการโยกย้ายสำหรับแอปใด ๆ เพียงแค่ขยายคำสั่งและส่งกลับNoneสำหรับgetitemฟังก์ชันและทำเช่นเดียวกันที่DATABASESนั่นคือสิ่งที่ถูกต้องที่คุณต้องทำ

PS:สำหรับคำสั่งคุณต้องระบุ--setting=module.path.settings_test_snippetหลังจากtest PPSหากคุณกำลังทำงานร่วมกับpycharm, ไม่ได้ตั้งค่า--settings ตัวเลือกที่Run/Debug configurationsเพียงแค่เพิ่มเส้นทางของsettings_test_snippet.pyการตั้งค่าที่กำหนดเอง แค่นั้นเอง !!

สนุก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.