Django के परीक्षण डेटाबेस को केवल मेमोरी में कैसे चलाएं?


125

मेरे Django इकाई परीक्षणों को चलने में लंबा समय लगता है, इसलिए मैं इसे गति देने के तरीकों की तलाश कर रहा हूं। मैं स्थापित करने पर विचार कर रहा हूं एसएसडी , लेकिन मुझे पता है कि इसके डाउनसाइड भी हैं। बेशक, ऐसी चीजें हैं जो मैं अपने कोड के साथ कर सकता हूं, लेकिन मैं एक संरचनात्मक सुधार की तलाश कर रहा हूं। यहां तक ​​कि एकल परीक्षण चलाने की गति धीमी है क्योंकि डेटाबेस को हर बार फिर से बनाया जाना चाहिए / दक्षिण में माइग्रेट किया जाना चाहिए। तो यहाँ मेरा विचार है ...

चूंकि मुझे पता है कि परीक्षण डेटाबेस हमेशा काफी छोटा होगा, इसलिए मैं सिर्फ रैम में पूरे परीक्षण डेटाबेस को रखने के लिए सिस्टम को कॉन्फ़िगर क्यों नहीं कर सकता हूं? कभी भी डिस्क को टच न करें। मैं इसे Django में कैसे कॉन्फ़िगर करूं? मैं MySQL का उपयोग करना पसंद करूंगा क्योंकि उत्पादन में मैं इसका उपयोग करता हूं, लेकिन अगर SQLite  3 या कुछ और यह आसान बनाता है, तो मैं उस रास्ते पर जाऊंगा।

क्या SQLite या MySQL में पूरी तरह से मेमोरी चलाने का विकल्प है? रैम डिस्क को कॉन्फ़िगर करना और फिर उसका डेटा स्टोर करने के लिए परीक्षण डेटाबेस को कॉन्फ़िगर करना संभव होना चाहिए, लेकिन मुझे यकीन नहीं है कि एक निश्चित डेटाबेस के लिए एक अलग डेटा निर्देशिका का उपयोग करने के लिए Django / MySQL को कैसे बताया जाए, खासकर जब से यह मिटता रहता है और प्रत्येक रन को फिर से बनाया। (मैं मैक एफडब्ल्यूआईडब्ल्यू पर हूं।)

जवाबों:


164

यदि आप अपने डेटाबेस इंजन को अपने परीक्षण चलाते समय sqlite3 में सेट करते हैं, तो Django एक इन-मेमोरी डेटाबेस का उपयोग करेगा

मैं settings.pyअपने परीक्षण चलाते समय इंजन को साइक्लाइट में सेट करने के लिए इस तरह कोड का उपयोग कर रहा हूं :

if 'test' in sys.argv:
    DATABASE_ENGINE = 'sqlite3'

या Django 1.2 में:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'sqlite3'}

और अंत में Django 1.3 और 1.4 में:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}

(बैकेंड के लिए पूर्ण पथ Django 1.3 के साथ कड़ाई से आवश्यक नहीं है, लेकिन सेटिंग को आगे संगत बनाता है।)

यदि आपको दक्षिण पलायन की समस्या हो रही है, तो आप निम्न पंक्ति भी जोड़ सकते हैं:

    SOUTH_TESTS_MIGRATE = False

9
हाँ बिल्कुल। मुझे अपने जवाब में यह कहना चाहिए था! संयोजन करें कि SOUTH_TESTS_MIGRATE = गलत और आपके परीक्षण बहुत तेज़ होने चाहिए।
एटिएन

7
इस है भयानक। django के नए सेटअप इस लाइन का उपयोग करते हैं: 'Engine': 'sqlite3' यदि 'sys.argv में' परीक्षण 'और' django.db.backends.mysql ',
mjallday

3
@ टॉमाज़ ज़िलिंस्की - हम्म, यह निर्भर करता है कि आप क्या परीक्षण कर रहे हैं। लेकिन मैं पूरी तरह से सहमत हूं कि, अंत में और समय-समय पर, आपको अपने वास्तविक डेटाबेस (पोस्टग्रेज, मायक्यूएल, ओरेकल ...) के साथ परीक्षण चलाने की आवश्यकता है। लेकिन साइक्लाइट के साथ अपने टेस्ट इन-मेमोरी को चलाने से आपका काफी समय बच सकता है।
एटिने

3
मैं -1 से +1 को उलट देता हूं: जैसा कि मैंने अभी देखा, क्विक रन के लिए साइक्लाइट का उपयोग करना और जैसे दैनिक परीक्षण के लिए MySQL पर स्विच करना बहुत तेज है। (ध्यान दें कि मुझे मतदान को अनलॉक करने के लिए एक डमी संपादित करना था)
टॉमाज़ ज़िलिस्की

12
इसके साथ सावधानी "test" in sys.argv; जब आप इसे नहीं चाहते, तो यह ट्रिगर हो सकता है manage.py collectstatic -i testsys.argv[1] == "test"एक अधिक सटीक स्थिति है जिसमें उस समस्या को नहीं होना चाहिए।
केटर्न

83

मैं आम तौर पर परीक्षणों के लिए एक अलग सेटिंग फ़ाइल बनाता हूं और इसका उपयोग परीक्षण कमांड जैसे में करता हूं

python manage.py test --settings=mysite.test_settings myapp

इसके दो लाभ हैं:

  1. आपको testsys.argv में या ऐसे किसी भी जादुई शब्द की जांच करने की आवश्यकता नहीं है , test_settings.pyबस हो सकता है

    from settings import *
    
    # make tests faster
    SOUTH_TESTS_MIGRATE = False
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}

    या फिर आप अपनी आवश्यकताओं के लिए इसे साफ़ कर सकते हैं, परीक्षण सेटिंग्स को उत्पादन सेटिंग्स से साफ़ कर सकते हैं।

  2. एक और लाभ यह है कि आप सूक्ष्म बग से बचने के लिए sqlite3 के बजाय उत्पादन डेटाबेस इंजन के साथ परीक्षण चला सकते हैं, इसलिए उपयोग विकसित करते समय

    python manage.py test --settings=mysite.test_settings myapp

    और एक बार कोड चलाने से पहले

    python manage.py test myapp

    बस यह सुनिश्चित करने के लिए कि सभी परीक्षण वास्तव में गुजर रहे हैं।


2
मुझे यह तरीका पसंद है। मेरे पास विभिन्न सेटिंग्स फ़ाइलों का एक गुच्छा है और विभिन्न सर्वर वातावरणों के लिए उनका उपयोग करते हैं, लेकिन मैंने एक अलग परीक्षण डेटाबेस चुनने के लिए इस पद्धति का उपयोग करने के बारे में नहीं सोचा था। विचार के लिए धन्यवाद।
एलेक्सिस बेलिडो

हाय अनुराग, मैंने यह कोशिश की, लेकिन सेटिंग्स में उल्लिखित मेरे अन्य डेटाबेस भी निष्पादित किए गए हैं। मैं सही कारण का पता नहीं लगा पा रहा हूं।
भूपेश पंत

अच्छा उत्तर। मुझे आश्चर्य है कि कवरेज के माध्यम से परीक्षण चलाने पर सेटिंग्स फ़ाइल को कैसे निर्दिष्ट किया जाए।
Wtower

यह एक अच्छा तरीका है, लेकिन DRY नहीं। Django पहले से ही जानता है कि आप परीक्षण चला रहे हैं। यदि आप इस ज्ञान को किसी भी तरह 'हुक' कर सकते हैं, तो आप सेट हो जाएंगे। दुर्भाग्य से, मेरा मानना ​​है कि प्रबंधन आदेश का विस्तार करने की आवश्यकता है। संभवतः फ्रेमवर्क के मूल में इस जेनेरिक को बनाने के लिए समझदारी होगी, उदाहरण के लिए, जब मैनेजमेण्ट को बुलाया जाता है, या उस प्रभाव के लिए कुछ करने के लिए वर्तमान कमांड पर सेट MANAGEMENT_COMMAND।
डायलनयुंग

2
@DylanYoung आप इसे मुख्य सेटिंग में test_settings में शामिल करके और परीक्षण के लिए इच्छित चीज़ों को ओवरराइड करके इसे सूखा बना सकते हैं।
अनुराग उनियाल

22

MySQL "मेमोरी" नामक एक स्टोरेज इंजन का समर्थन करता है, जिसे आप अपने डेटाबेस कॉन्फिगर ( settings.py) में कॉन्फ़िगर कर सकते हैं:

    'USER': 'root',                      # Not used with sqlite3.
    'PASSWORD': '',                  # Not used with sqlite3.
    'OPTIONS': {
        "init_command": "SET storage_engine=MEMORY",
    }

ध्यान दें कि मेमोरी स्टोरेज इंजन बूँद / टेक्स्ट कॉलम का समर्थन नहीं करता है, इसलिए यदि आप इसका उपयोग कर रहे हैं तो django.db.models.TextFieldयह आपके लिए काम नहीं करेगा।


5
बूँद / पाठ कॉलम के लिए समर्थन की कमी का उल्लेख करने के लिए +1। यह लेनदेन ( dev.mysql.com/doc/refman/5.6/en/memory-storage-engine.html ) का समर्थन करने के लिए भी प्रतीत नहीं होता है ।
तुक्का मुस्टोनन

यदि आप वास्तव में इन-मेमरी टेस्ट चाहते हैं, तो आप शायद बेहतर है कि आप कम से कम लेन-देन का समर्थन करने वाले साइक्लाइट के साथ जाएं।
एटॉमिक77

15

मैं आपके मुख्य प्रश्न का उत्तर नहीं दे सकता, लेकिन कुछ चीजें हैं जो आप चीजों को गति देने के लिए कर सकते हैं।

सबसे पहले, सुनिश्चित करें कि आपका MySQL डेटाबेस InnoDB का उपयोग करने के लिए सेट है। फिर यह प्रत्येक परीक्षण से पहले डीबी की स्थिति को रोलबैक करने के लिए लेनदेन का उपयोग कर सकता है, जिससे मेरे अनुभव में बड़े पैमाने पर गति हुई है। आप अपनी सेटिंग्स में डेटाबेस इनिट कमांड पारित कर सकते हैं (Django 1.2 सिंटैक्स):

DATABASES = {
    'default': {
            'ENGINE':'django.db.backends.mysql',
            'HOST':'localhost',
            'NAME':'mydb',
            'USER':'whoever',
            'PASSWORD':'whatever',
            'OPTIONS':{"init_command": "SET storage_engine=INNODB" } 
        }
    }

दूसरे, आपको हर बार दक्षिण प्रवास चलाने की आवश्यकता नहीं है। SOUTH_TESTS_MIGRATE = Falseअपनी सेटिंग में सेट करें और डेटाबेस को सादी syncdb के साथ बनाया जाएगा, जो सभी ऐतिहासिक माइग्रेशन के माध्यम से चलने की तुलना में बहुत तेज होगा।


महान टिप! यह मेरे परीक्षण कम 369 tests in 498.704sकरने के लिए 369 tests in 41.334s । यह 10 गुना से अधिक तेज है!
१u बजे गाबी पुरकारु

क्या Django 1.7+ में माइग्रेशन के लिए settings.py में एक समान स्विच है?
एडवर्ड नेवेल

@EdwardNewell बिल्कुल नहीं। लेकिन आप --keepडेटाबेस को जारी रखने के लिए उपयोग कर सकते हैं और हर टेस्ट रन पर आपके संपूर्ण माइग्रेशन को फिर से लागू करने की आवश्यकता नहीं है। नए माइग्रेशन अभी भी चलेंगे। यदि आप बार-बार शाखाओं के बीच स्विच कर रहे हैं, तो असंगत स्थिति में आना आसान है हालांकि (डेटाबेस को परीक्षण डेटाबेस में बदलने और चलाने से पहले आप नए माइग्रेशन को वापस कर सकते हैं migrate, लेकिन यह थोड़ा दर्द है)।
डायलनयुंग

10

आप डबल ट्विकिंग कर सकते हैं:

  • ट्रांसेक्शनल टेबल का उपयोग करें: प्रारंभिक फिक्स्चर राज्य को हर टेस्टकेस के बाद डेटाबेस रोलबैक का उपयोग करके सेट किया जाएगा।
  • अपने डेटाबेस डेटा को रैमडिस्क पर रखें: आप बहुत लाभ प्राप्त करेंगे जहाँ तक डेटाबेस निर्माण का संबंध है और रनिंग टेस्ट भी तेज़ होगा।

मैं दोनों तरकीबों का इस्तेमाल कर रहा हूं और मैं काफी खुश हूं।

इसे Ubuntu पर MySQL के लिए कैसे सेट करें:

$ sudo service mysql stop
$ sudo cp -pRL /var/lib/mysql /dev/shm/mysql

$ vim /etc/mysql/my.cnf
# datadir = /dev/shm/mysql
$ sudo service mysql start

खबरदार, यह सिर्फ परीक्षण के लिए है, आपके डेटाबेस को मेमोरी से रिबूट करने के बाद खो गया है!


धन्यवाद! मेरे लिये कार्य करता है। मैं sqlite का उपयोग नहीं कर सकता, क्योंकि मैं mysql (पूर्ण-पाठ अनुक्रमित) के लिए विशिष्ट सुविधाओं का उपयोग कर रहा हूं। Ubuntu यूजर्स के लिए, आपको mysqld को / dev / shm / mysql तक पहुंच प्रदान करने के लिए अपने एपर्मोर कॉन्फिगर को एडिट करना होगा
इवान विराबीयन

इवान और पोटर के सिर के लिए चीयर्स। अभी के लिए AppArmor mysql प्रोफ़ाइल को अक्षम करें, लेकिन संबंधित स्थानीय प्रोफ़ाइल को अनुकूलित करने के लिए एक मार्गदर्शिका मिली: blogs.oracle.com/jsmyth/entry/apparmor_and_mysql
trojjor

हम्म। मैंने mysqld को / dev / shm / mysql पथ और उसकी सामग्री तक पहुँच देने के लिए स्थानीय प्रोफ़ाइल को अनुकूलित करने की कोशिश की है, लेकिन सेवा केवल 'शिकायत' मोड (आ-शिकायत कमांड) में शुरू हो सकती है और कुछ के लिए 'लागू नहीं' कर सकती है। कारण ... एक और मंच के लिए एक सवाल! मैं यह नहीं समझ सकता कि कैसे कोई 'शिकायत' नहीं है जब यह काम करता है, इसका मतलब है कि mysqld प्रोफ़ाइल का उल्लंघन नहीं कर रहा है ...
trojjer

4

एक अन्य दृष्टिकोण: एक अस्थायी उदाहरण में MySQL का एक और उदाहरण है जो RAM डिस्क का उपयोग करता है। इस ब्लॉग पोस्ट में निर्देश: Django में परीक्षण के लिए MySQL को तेज करना

लाभ:

  • आप उसी डेटाबेस का उपयोग करते हैं जो आपके उत्पादन सर्वर का उपयोग करता है
  • अपने डिफ़ॉल्ट mysql कॉन्फ़िगरेशन को बदलने की कोई आवश्यकता नहीं है

2

अनुराग के उत्तर पर विस्तार करते हुए मैंने समान test_settings बनाकर और प्रबंधन को निम्नलिखित जोड़कर प्रक्रिया को सरल बनाया

if len(sys.argv) > 1 and sys.argv[1] == "test":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.test_settings")
else:
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

लगता है कि sys पहले से ही इंपोर्टेड है और manage.py का उपयोग केवल कमांड लाइन के माध्यम से किया जाता है, इसलिए सेटिंग्स को अव्यवस्थित करने की कोई आवश्यकता नहीं है


2
इसके साथ सावधानी "test" in sys.argv; जब आप इसे नहीं चाहते, तो यह ट्रिगर हो सकता है manage.py collectstatic -i testsys.argv[1] == "test"एक अधिक सटीक स्थिति है जिसमें उस समस्या को नहीं होना चाहिए।
केटर्न

2
@ इस तरह से यह ./manage.pyतर्क के बिना चलने पर एक अपवाद उत्पन्न करता है (जैसे कि कौन से प्लग उपलब्ध हैं, यह देखने के लिए --help)
एंटनी हैचकिंस

1
@AntonyHatchkins यह हल करने के लिए तुच्छ है:len(sys.argv) > 1 and sys.argv[1] == "test"
DylanYoung

1
@DylanYoung हाँ, यह वही है जो मैं चाहता था कि एल्विन उसके समाधान में शामिल हो लेकिन वह इसे सुधारने में विशेष रुचि नहीं रखता है। वैसे भी यह कानूनी समाधान की तुलना में एक त्वरित हैक की तरह दिखता है।
एंटनी हैचकिंस

1
थोड़ी देर में इस जवाब को नहीं देखा, मैंने @ DylanYoung के सुधार को प्रतिबिंबित करने के लिए स्निपेट को अपडेट किया
एल्विन

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.