2010-06-22 101 views
112

我的Django單元測試需要很長時間才能運行,所以我正在尋找加快速度的方法。我正在考慮安裝SSD,但我知道它也有缺點。當然,我可以用我的代碼做些事情,但我正在尋找結構性修復。即使運行單個測試也很慢,因爲每次都需要重建/南遷數據庫。所以這裏是我的主意......如何僅在內存中運行Django的測試數據庫?

因爲我知道測試數據庫總是很小,爲什麼我不能配置系統始終將整個測試數據庫保存在RAM中?切勿觸摸磁盤。我如何在Django中配置它?我寧願繼續使用MySQL因爲這是我在生產中使用的,但如果SQLite   3或其他東西使這容易,我會這樣。

SQLite或MySQL有一個選項可以完全在內存中運行嗎?應該可以配置RAM磁盤,然後配置測試數據庫以在其中存儲其數據,但我不知道如何告訴Django/MySQL爲某個數據庫使用不同的數據目錄,尤其是因爲它一直在擦除並重新創建每個運行。 (我在Mac FWIW。)

回答

151

如果您在運行測試時將數據庫引擎設置爲sqlite3,Django will use a in-memory database

我用我的settings.py這樣的代碼來設置發動機運行的SQLite我測試時:

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不完全需要後端的完整路徑,bu t使設置向前兼容。)

您還可以添加以下行,如果您有問題與南非遷移:

SOUTH_TESTS_MIGRATE = False 
+0

你把它放在你的settings.py中嗎? – Leopd 2010-06-23 20:34:56

+9

是的,確切地說。我應該把它放在我的答案中!將其與SOUTH_TESTS_MIGRATE = False結合起來,你的測試應該快得多。 – Etienne 2010-06-24 19:19:01

+0

太棒了!有了這兩個更改,我的系統中運行單個快速測試的開銷從12秒降到<100ms。 – Leopd 2010-06-24 19:58:53

22

MySQL支持這樣所謂的 「MEMORY」 的存儲引擎,你可以在你的數據庫配置(settings.py)配置:

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

注意,存儲器存儲引擎不支持blob/text列,所以如果您使用的是django.db.models.TextField,這不適用於您。

+5

+1提缺乏支持BLOB /文本完全相同的數據庫列。它似乎也不支持事務(http://dev.mysql.com/doc/refman/5.6/en/memory-storage-engine.html)。 – 2011-06-10 06:27:42

+0

如果你真的想要內存中的測試,那麼最好使用至少支持事務的sqlite。 – atomic77 2018-01-23 20:54:33

15

我無法回答你的主要問題,但有幾件事情你可以做,以加快速度。

首先,確保您的MySQL數據庫設置爲使用InnoDB。然後它可以使用事務在每次測試之前回滾db的狀態,這在我的經驗中導致了大幅加速。你可以在你的settings.py通過數據庫init命令(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" } 
     } 
    } 

其次,你不需要每次運行南方遷移。在settings.py中設置SOUTH_TESTS_MIGRATE = False,數據庫將使用普通的syncdb創建,這比運行所有歷史遷移要快得多。

+0

偉大的提示!它將我的測試從498.704s的369次測試減少到41.334s的369次測試。這比以前快了10倍! – 2012-01-04 10:17:53

+0

Django 1.7+中是否存在用於遷移的settings.py中的等效開關? – 2015-03-10 20:25:03

+0

@EdwardNewell不完全。但是您可以使用'--keep'來保存數據庫,並且不需要在每次測試運行時重新應用您的完整遷移集。新的遷移仍將繼續。如果你頻繁地在分支之間切換,很容易陷入不一致的狀態(你可以在切換之前通過將數據庫更改爲測試數據庫並運行'migrate'來恢復新的遷移,但這有點痛苦)。 – DylanYoung 2017-12-13 18:44:39

9

你可以做雙扭捏:

  • 使用事務性表:初始燈具狀態會在每個TestCase之後使用數據庫回滾進行設置。
  • 把你的數據庫數據目錄放在ramdisk上:就數據庫創建而言,你會獲得很多,運行測試也會更快。

我正在使用這兩種技巧,我很高興。

如何設置它爲MySQL在Ubuntu:

$ 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 

當心,這只是用於測試,後重新啓動數據庫從內存丟失!

+0

謝謝!爲我工作。我不能使用sqlite,因爲我正在使用特定於mysql的功能(全文索引)。 對於ubuntu用戶,你必須編輯你的apparmor配置,以允許mysqld訪問到/ dev/shm/mysql – 2011-05-04 09:47:17

+0

爲Ivan和Potr高舉歡呼聲。現在禁用AppArmor的mysql配置文件,但找到了一個定製相關本地配置文件的指南:https://blogs.oracle.com/jsmyth/entry/apparmor_and_mysql – trojjer 2013-08-01 10:57:23

+0

嗯。我試過定製本地配置文件,以便爲/ dev/shm/mysql路徑及其內容提供mysqld訪問權限,但服務只能以'抱怨'模式(aa-complain命令)啓動,而不是「強制執行」理由......另一個論壇的問題!我無法理解的是,當它工作時,沒有任何「投訴」,這意味着mysqld不會違反配置文件... – trojjer 2013-08-01 11:03:30

78

我通常爲測試創建一個單獨的設置文件並在測試命令中使用它,例如

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

它有兩個好處:

  1. 您不必檢查test或任何這樣神奇的字眼在sys.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

我喜歡這種方法。我有一堆不同的設置文件,並將它們用於不同的服務器環境,但我沒有想過使用此方法選擇不同的測試數據庫。感謝這個想法。 – 2013-07-19 21:02:50

+0

嗨Anurag,我試過這個,但我的其他數據庫中提到的設置也執行。我無法弄清楚確切的原因。 – 2014-06-11 13:20:13

+0

很好的答案。我想知道如何在覆蓋範圍內運行測試時指定設置文件。 – Wtower 2015-03-10 13:32:40

2

上阿努拉格的答案擴展我創建相同test_settings和添加簡化了操作步驟如下,以manage.py

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僅通過使用命令行,因此不需要混亂設置

+0

這是怎麼讓你跑你的生產分貝? – boatcoder 2012-10-25 22:19:17

+0

需要擴展到 - 或者你可以通過命令行手動設置設置文件 - 你經常測試的問題 – Alvin 2012-10-26 06:39:29

+0

我喜歡這種方法,但要清楚,將通過--settings = mysite .settings使用設置而不是test_settings? – yellottyellott 2013-04-03 04:54:13

3

另一種方法:讓另一個MySQL實例運行在使用RAM磁盤的臨時文件中。本博客中的說明:Speeding up MySQL for testing in Django

優點:

  • 您可以使用您的生產服務器使用
  • 沒有必要改變你的MySQL默認配置
相關問題