摘要:在中可以在設(shè)置數(shù)據(jù)庫重裝操作這樣就可以在每一個中定義本次污染的數(shù)據(jù)表,保證下一個在運行前重刷下被污染的數(shù)據(jù)表,如這樣會極大提高數(shù)據(jù)庫測試效率,不推薦使用給出的和,效率并不高。
本文主要探討寫數(shù)據(jù)庫測試。
寫laravel程序時,除了寫生產(chǎn)代碼,還需要寫測試代碼。其中,寫數(shù)據(jù)庫測試比較麻煩,因為需要針對每一個test case需要建立好數(shù)據(jù)集,該次test case污染的數(shù)據(jù)表還需要恢復(fù)現(xiàn)場,避免影響下一個test case運行,同時還得保證性能問題,否則隨著程序不斷膨脹,測試數(shù)量也越多,那每一次測試運行需要花費大量時間。
有兩個比較好的方法可以提高數(shù)據(jù)庫測試性能:
對大量的tests按照功能分組。如有1000個tests,可以按照業(yè)務(wù)功能分組,如group1:1-200, group2:201-800, group3: 801-1000。這樣可以并發(fā)運行每組測試包裹。
只恢復(fù)每個test case污染的表,而不需要把所有的數(shù)據(jù)表重新恢復(fù),否則表數(shù)量越多測試代碼執(zhí)行越慢。
這里聊下方法2的具體做法。
假設(shè)程序有50張表,每次運行測試時首先需要為每組構(gòu)建好獨立的對應(yīng)數(shù)據(jù)庫,然后創(chuàng)建數(shù)據(jù)表,最后就是填充測試數(shù)據(jù)(fixtures)。fixtures可用yml格式定義,既直觀也方便維護(hù),如:
#simple.yml accounts: - id: 1 person_id: 2 type: investment is_included: true - id: 2 person_id: 2 type: investment is_included: true transactions: - account_id: 1 posted_date: "2017-01-01" amount: 10000 transaction_category_id: 1 - account_id: 2 posted_date: "2017-01-02" amount: 10001 transaction_category_id: 2
然后需要寫個yamlSeeder class來把數(shù)據(jù)集填充到臨時數(shù)據(jù)庫里:
abstract class YamlSeeder extends IlluminateDatabaseSeeder { private $files; public function __construct(array $files) { $this->files = $files } public function run(array $tables = []): void { // Close unique and foreign key constraint $db = $this->container["db"]; $db->statement("SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;"); $db->statement("SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;"); foreach($this->files as $file) { ... // Convert yaml data to array $fixtures = SymfonyComponentYamlYaml::parse(file_get_contents($file)); ... foreach($fixtures as $table => $data) { // Only seed specified tables, it is important!!! if ($tables && !in_array($table, $tables, true)) { continue; } $db->table($table)->truncate(); if (!$db->table($table)->insert($data)) { throw new RuntimeException("xxx"); } } ... } // Open unique and foreign key constraint $db->statement("SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;"); $db->statement("SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;"); } } class SimpleYamlSeeder extends YamlSeeder { public function __construct() { parent::__construct([database.path("seeds/simple.yml")]); } }
上面的代碼有一個關(guān)鍵處是參數(shù)$tables:如果參數(shù)是空數(shù)組,就把所有數(shù)據(jù)表數(shù)據(jù)插入隨機(jī)數(shù)據(jù)庫里;如果是指定的數(shù)據(jù)表,只重刷指定的數(shù)據(jù)表。這樣會很大提高數(shù)據(jù)庫測試的性能,因為可以在每一個test case里只需要指定本次測試所污染的數(shù)據(jù)表。在tests/TestCase.php中可以在setUp()設(shè)置數(shù)據(jù)庫重裝操作:
abstract class TestCase extends IlluminateFoundationTestingTestCase { protected static $tablesToReseed = []; public function seed($class = "DatabaseSeeder", array $tables = []): void { $this->artisan("db:seed", ["--class" => $class, "--tables" => implode(",", $tables)]); } protected function reseed(): void { // TEST_SEEDERS is defined in phpunit.xml, e.g.$seeders = env("TEST_SEEDERS") ? explode(",", env("TEST_SEEDERS")) : []; if ($seeders && is_array(static::$tablesToReseed)) { foreach ($seeders as $seeder) { $this->seed($seeder, static::$tablesToReseed); } } Cache::flush(); static::$tablesToReseed = false; } protected static function reseedInNextTest(array $tables = []): void { static::$tablesToReseed = $tables; } }
這樣就可以在每一個test case中定義本次污染的數(shù)據(jù)表,保證下一個test case在運行前重刷下被污染的數(shù)據(jù)表,如:
final class AccountControllerTest extends TestCase { ... public function testUpdateAccount() { static::reseedInNextTest([Account::class, Transaction::class]); ... } }
這樣會極大提高數(shù)據(jù)庫測試效率,不推薦使用Laravel給出的IlluminateFoundationTestingDatabaseMigrations 和 IlluminateFoundationTestingDatabaseTransactions,效率并不高。
laravel的db:seed命令沒有--tables這個options,所以需要擴(kuò)展IlluminateDatabaseConsoleSeedsSeedCommand:
class SeedCommand extends IlluminateDatabaseConsoleSeedsSeedCommand { public function fire() { if (!$this->confirmToProceed()) { return; } $this->resolver->setDefaultConnection($this->getDatabase()); Model::unguarded(function () { $this->getSeeder()->run($this->getTables()); }); } protected function getTables() { $tables = $this->input->getOption("tables"); return $tables ? explode(",", $tables) : []; } protected function getOptions() { $options = parent::getOptions(); $options[] = ["tables", null, InputOption::VALUE_OPTIONAL, "A comma-separated list of tables to seed, all if left empty"]; return $options; } }
當(dāng)然還得寫SeedServiceProvider()來覆蓋原有的IlluminateFoundationProvidersConsoleSupportServiceProvider::registerSeedCommand()中注冊的command.seed,然后在config/app.php中注冊:
class SeedServiceProvider extends ServiceProvider { /** * Indicates if loading of the provider is deferred. * * @var bool */ protected $defer = true; /** * @see IlluminateDatabaseSeedServiceProvider::registerSeedCommand() */ public function register() { $this->app->singleton("command.seed", function ($app) { return new SeedCommand($app["db"]); }); $this->commands("command.seed"); } public function provides() { return ["command.seed"]; } }
OK,這樣所有的工作都做完了。。以后寫數(shù)據(jù)庫測試性能會提高很多,大量的test case可以在短時間內(nèi)運行完畢。
最后,寫測試代碼是必須的,好處非常多,隨著項目程序越來越大,就會深深感覺到寫測試是必須的,一勞永逸,值得花時間投資。也是作為一名軟件工程師的必備要求。
RightCapital招聘Laravel DevOps
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/23105.html
摘要:本文主要探討數(shù)據(jù)庫測試。在寫測試代碼一中聊了關(guān)于如何提高數(shù)據(jù)庫測試性能,其實簡單一句就是每一個只重新被污染的表。最后還得在中創(chuàng)建用戶并授權(quán),以用戶登錄這樣就臨時測試數(shù)據(jù)庫就準(zhǔn)備完畢了,然后就是測試數(shù)據(jù),執(zhí)行,執(zhí)行等等,可以參考寫測試代碼一。 本文主要探討數(shù)據(jù)庫測試。 在寫Laravel測試代碼(一) 中聊了關(guān)于如何提高 laravel 數(shù)據(jù)庫測試性能,其實簡單一句就是:每一個test ...
摘要:寫一個,的是,的內(nèi)容參照寫測試代碼三,然后寫上很明顯,這里測試的是,即和,是一個自定義的,主要功能就是實現(xiàn)了全部,并保存在文件里作為。 本文主要探討寫laravel integration/functional test cases時候,如何assert。前面幾篇文章主要聊了如何reseed測試數(shù)據(jù),mock數(shù)據(jù),本篇主要聊下assert的可行實踐,盡管laravel官方文檔聊了Tes...
摘要:用也有三四個月了,雖然是兼職開發(fā),但是使用的頻率非常之高,畢竟是產(chǎn)品化的一個項目。第二階段數(shù)據(jù)庫和開發(fā)了比較多的功能之后,會發(fā)現(xiàn)需要大量的測試數(shù)據(jù),這時候和就該大顯身手了。 用Laravel也有三四個月了,雖然是兼職開發(fā),但是使用的頻率非常之高,畢竟是產(chǎn)品化的一個項目。在這期間,也踩了無數(shù)的坑,走了很多彎路,所以準(zhǔn)備把最近的感悟記錄下來,方便后來者。 第一階段:簡單的增刪改查 這是最...
摘要:如何在實戰(zhàn)中能應(yīng)用上設(shè)計模式,我思考了接近兩年。最開始我接觸設(shè)計模式,出發(fā)點就是為了重構(gòu)代碼,以便更好的復(fù)用和測試。也就是說基本是被當(dāng)成一組靜態(tài)函數(shù)使用的。 MVC是Laravel自帶的,大家也多少都會用一些。今天我們不談MVC,談一些大中型項目的設(shè)計思路。 前言 雖然標(biāo)題說是設(shè)計模式,但是我并不打算去講什么singleton、strategy、factory,不知道為什么,每次看到...
摘要:本文首發(fā)于作者這是一篇基礎(chǔ)教程,對標(biāo)文檔中的數(shù)據(jù)遷移和數(shù)據(jù)填充。那么,中的數(shù)據(jù)庫遷移概念,就是用于解決團(tuán)隊中保證數(shù)據(jù)庫結(jié)構(gòu)一致的方案。和不同,如果多次執(zhí)行就會進(jìn)行多次數(shù)據(jù)填充。好了,數(shù)據(jù)遷移和數(shù)據(jù)填充的基本操作也就這些了。 showImg(https://segmentfault.com/img/remote/1460000012252769?w=648&h=422); 本文首發(fā)于 h...
閱讀 2007·2023-04-25 16:53
閱讀 1448·2021-10-13 09:39
閱讀 615·2021-09-08 09:35
閱讀 1650·2019-08-30 13:03
閱讀 2129·2019-08-30 11:06
閱讀 1839·2019-08-30 10:59
閱讀 3197·2019-08-29 17:00
閱讀 2296·2019-08-23 17:55