單元測試是獨立的,所謂的獨立是指有獨立的運行容器,獨立的數據庫。
這樣做有什么好處呢?
(1). 不會跟正常的容器產生沖突,繼而影響正常業務。
(2). 數據庫獨立防止數據被修改影響單元測試結果。
這兩天攻克了單元測試的兩個問題:模擬數據庫、mockery的調用。現在把原理解析一下。
1. 模擬數據庫
那這樣,我們來想一下。正常的創建一個數據庫要有那些流程?
(1)定義表結構
(2)往表中插入數據
其實測試使用的模擬數據庫總的來說也就這兩個流程。
來來來,敲黑板,重點來了。
database目錄下有三個文件夾,migrations中存儲的是表結構文件,factories中存儲的是創建模擬數據的方法,seeds沒研究,暫時不知道干啥用的。
這個時候可能會有人問:創建表結構文件是什么雞兒?它有啥用啊。
我們這樣想一下:我們要創建模擬數據庫,那數據庫中肯定要有表吧。表長什么樣子呢?你不給定義laravel怎么知道呢?那在哪里定義呢?就在migrations下面定義!!!
來給大家舉個例子:
看見這個文件沒?它就是定義表結構的地方。它長這個樣子:
我們再仔細看看這個文件名:
哇,這名字這么長。還有日期,中間還有一串數字,讓我怎么寫嘛。
兄弟,別急。我有一計可保你平安。
在項目下面執行這句話:你就會得到你想要的結果
php artisan make:migration test --path=database/migrations/pandaRead
look here:
創建了新的文件,有木有,有木有。然后你就可以在up中寫你表結構的定義了。
有同學可能會問這表里面的東西都是干啥的呀?作者雲:內事不決問百度,外事不決問谷歌。
知道了為啥定義表結構和怎么設定表結構。
這個時候可能又會有兄弟問了:唉,你這個migrations下面為啥還有個pandaRead目錄啊?你創建它干啥啊?
問的好!!!
一個大型的項目它所涉及到的數據庫往往不止一個,而且各個數據庫涉及到的業務往往不交叉,所以我們往往只會模擬一個數據庫中的所有表。如果一次性的把所有數據庫中的所有表都創建了,會很浪費資源。因此:給每個庫定義一個文件夾,文件夾下面存儲某個庫下面的表結構文件,這樣你在加載數據的時候可以根據文件夾把涉及到的所有表都一下子給創建了。
那又會有同學問了,什么時候創建表呢?表創建在哪里呢?
我就喜歡你這樣問題多的小朋友!!!
來來來,諸位看官且把目光移到這里。
看到TestCase這個類了嗎?它將會是你創建的所有測試文件的父類!!
那舉個例子:
看到了沒,所有的類都繼承了TestCase這個類。
那我們是不是可以想:既然所有的類都繼承了TestCase這個類,那我們的配置是不是可以寫到TestCase這里呢?當然可以!!!
等等???什么配置,我還沒反應過來怎么就講到配置了呢?
小老弟,別急。來來來,看這里,思考這幾個問題:
(1)我們的表創建在哪里呢?創建到文件里?數據庫里?還是內存里?我們要在哪里告訴系統呢?
(2)剛才我們定義了表結構文件,但是定義了並沒有加載啊。在哪里加載他們呢?
想明白了嗎?這些東西我們都要告訴laravel,不然即使laravel再強大,它也無能為力啊!!!
那在哪里告訴它呢?敲黑板,敲黑板,重點來了哈。
我們來看看TestCase.php這個類中到底有什么東西。
創建表的地方,數據庫連接的方式都在這里配置。
創建表沒什么好講的了,我們來講講數據庫的連接方式:
config(['database.connections.mysql' => config('database.connections.testing')]);
這句話其實就是給數據庫添加配置:在database配置文件中,connections.mysql的配置
這樣數據庫的配置就搞定了。
別急我們再看下這個方法,一層一層的剝離下去,我們看看它到底做了什么
parent::setUp();
最終其實它創建了一個新的容器。
優秀啊,優秀啊!!!這樣你每執行一個單元測試的時候,都會創建一個新的容器,各個文件的單元測試之間就不會相互影響了。厲害啊
現在我們再來看看模擬數據:
這個時候可能會有人問:什么是模擬數據啊?你想啊,你測試是不是需要數據?數據誰來創建?你可以選擇自己創建,同時你也可以選擇交給機器去創建,那你要創建什么樣的數據呢?在哪里定義呢?你創建一條數據可以自己創建,創建10條也可以自己創建,那你要創建1000條,10000條呢?還自己創建嗎?這個時候你就需要機器來幫你做這件事情了!!
沒錯。就是在這里定義。舉個例子:
它里面是長這個樣子的。里面的數據根據你的需要自己配置。Generator可是很強大的啊啊啊啊啊啊!!!建議大家看看
諾,看見了沒?給那個類創建什么數據都在這里面定義好了。那什么時候插入呢?
看見沒,我們可以直接用工廠創建,然后最后可以直接插入到數據表中!!!讀取數據的方式就和平時讀取數據的方式一樣,沒什么區別了。
2. mockery
模擬數據庫講清楚了,那mockery呢?
什么叫mockery,什么時候用到mockery呢?
mockery......自己去查吧。
簡單的說你可以將mock理解為替換掉類中的某個方法,或者替換掉某個類。
看這里,我們mock掉了一個類的某個方法,然后重新在容器中綁定這個類,這樣容器中的類就被替換了,當我們測試的時候調用這個類的這個方法的時候,就直接按照我們mock的數據返回了,優秀啊!!!
本次分享,到這里就結束了,歡迎大家批評指正。