解決 Django 功能測試中資料會被清除的問題
不久前,山姆鍋開始學習 Django 這套 Web 應用框架,在不跳脫它既有有框架的情況下,運用它可以快速建構應用程式原型。差不多同一時間,也找到 Test-driven Development with Python 這本好書,書名雖然好像跟 Django 無關,但書中的範例程式是以 Django 為基礎。 可惜,本文不是要示範如何使用 Django 做功能測試,這個主題網路有許多文章可以參考。山姆鍋在使用 Django 的 LiveServerTestCase 時 發現資料庫的資料在第一個測試案例 (test case) 之後就會被清除,導致後續的測試無法正常運作。
Django 的功能性測試 (或者稱用戶驗收測試) 最常使用 Selenium
來驅動瀏覽器,並利用 django.test.LiveServerTestCase
在背景建立測試資料庫以及 WSGI 服務器。
如此,完成一個端到端 (end-to-end) 的測試環境,基本上可以模擬大多數用戶跟應用之間的互動情境。
這麼完整的支援,原本是該多麽理想啊! 本文的解決方法應該只適用 SQLite
3 。
執行環境
在說明山姆鍋遇到的問題前,需要先列出我的測試環境:
- Python 2.7.x
- Django 1.8.3
- SQLite 3
- OS: Mac OS X
注意使用的是 SQLite 3 資料庫。
問題描述
除了 LiveServerTestCase
支援功能測試外, Django
也對單元測試 (unit test) 提供有 django.test.TestCase
來協助撰寫。 TestCase
利用資料庫對於交易 (transaction) 的支援,在每次測試案例之後,還原資料庫到案例開始前的狀態,這樣來達到案例之間的分隔 (isolation) 目的。
基於一個山姆鍋還不了解的原因,畢竟山姆鍋對於 Django
還沒有那麼多經驗,LiveServerTestCase
不是使用資料庫的交易來還原狀態,
而是對資料庫進行清除動作,就是這個神秘的清除動作,導致在功能測試時只有第一個執行的案例能夠正常,
後續用到資料庫的案例都會發生讀不到資料的情況。
有人建議功能測試不要使用 SQLite 3,使用 MySQL 或者 PostgreSQL,
原因不外乎 SQLite 3 在功能測試不穩定等等。
可是山姆鍋打算開發的應用就需要使用 SQLite 3 啊!所以,並沒有針對 MySQL
或者 PostgreSQL 來測試過。
解決方法
山姆鍋採用的解決方法是直接繼承 TestCase
跟 LiveServerTestCase
這兩個類別,繼承
[TestCase` 使用資料庫交易來還原資料庫狀態, 使用 LiveServerTestCase
來設定測試用的 WSGI
服務器。這個新的類別很沒有創意地叫做 FunctionalTest
,原始碼如下:
1 | # -*- coding: utf-8 -*- |
結語
Django LiveServerTestCase
的這個問題困擾山姆鍋一陣子,網路上也沒有太多有用的資料。
本文的解法是參考 Fast functional testing with Django and Ghostrunner
這篇文章。
必須老實講,山姆鍋不知道這個問題的確切原因,也不知道有沒有其他解法,所以感覺真是不踏實。不管如何,希望對跟我遇到相同問題的人有所幫助。
參考資料
_`Django`: https://www.djangoproject.com/
_`Test-driven Development with Python`:
http://shop.oreilly.com/product/0636920029533.do
_`Selenium`: https://selenium-python.readthedocs.org/
_`SQLite 3`: https://docs.python.org/2/library/sqlite3.html
_`Fast functional testing with Django and Ghostrunner`:
https://wearespindle.com/articles/fast-functional-testing-with-django-and-ghostrunner/
_`原始的 LiveServerTestCase 實作`:
https://github.com/wearespindle/ghostrunner/blob/master/ghost/test/testcases.py