#DatabaseTransactions
Explore tagged Tumblr posts
sunshinedigitalservices · 23 days ago
Text
instagram
0 notes
shiprasharma2927 · 2 years ago
Text
Unraveling Laravel Test: Best Practices for Efficient Coding
Tumblr media
Laravel, a powerful PHP web framework, has gained immense popularity for its elegant syntax, robust features, and developer-friendly environment. One of its key strengths lies in its testing capabilities, allowing developers to ensure the reliability and stability of their applications through automated testing. In this article, we will delve into the world of Laravel testing and explore the best practices for efficient coding.
Understanding Laravel Testing
Laravel provides a comprehensive testing suite that supports both unit and feature testing. Unit tests focus on individual components, ensuring they function correctly in isolation, while feature tests assess the behavior of multiple components working together to achieve a specific functionality.
Testing in Laravel is built on the PHPUnit framework, offering a familiar environment for developers with experience in PHPUnit. Laravel's testing tools extend PHPUnit and provide additional functionalities tailored to the Laravel ecosystem.
Best Practices for Laravel Testing
1. Isolation and Dependency Management:
When writing unit tests, it's crucial to isolate the code under test from external dependencies. Laravel's dependency injection system facilitates the use of interfaces and dependency injection, allowing you to mock external services or dependencies. This promotes testing the specific behavior of the code without relying on external factors.
phpCopy code
// Example of dependency injection in Laravel public function __construct(ExternalServiceInterface $service) { $this->service = $service; }
2. Use Factories for Data Setup:
Laravel provides a convenient way to create model instances for testing purposes using factories. Factories allow you to generate realistic data for your tests, making it easier to simulate various scenarios and edge cases.
phpCopy code
// Example of using a factory in Laravel factory(User::class)->create();
3. Database Transactions for Speed:
Wrapping your tests in a database transaction can significantly improve test speed. Laravel automatically rolls back transactions after each test, ensuring that the database remains in a consistent state. This approach reduces the overhead of migrating and seeding the database for every test.
phpCopy code
// Example of using a database transaction in Laravel use Illuminate\Foundation\Testing\DatabaseTransactions; class ExampleTest extends TestCase { use DatabaseTransactions; }
4. Test Only What Matters:
Focus your tests on critical parts of your application. Prioritize testing business logic, validation, and key functionalities. Avoid testing Laravel's built-in features, as they are already covered by the framework's own tests.
5. Organize Tests Effectively:
Keep your test suite organized by following Laravel's naming conventions. Place your test files in the tests directory and ensure that the test file names correspond to the classes they are testing. Laravel's artisan command can generate test files with the make:test command.
bashCopy code
php artisan make:test ExampleTest
6. Continuous Integration (CI):
Integrate your Laravel tests into a continuous integration system to automate the testing process. This ensures that tests are run consistently on every code change, helping to catch issues early in the development cycle.
7. Documentation and Comments:
Write clear and concise documentation for your tests, explaining the purpose of each test and any specific conditions it addresses. Additionally, use comments within your test code to provide context for future developers.
Conclusion
Laravel's testing capabilities empower developers to build robust and reliable applications. By adhering to best practices such as isolation, effective data setup, database transactions, targeted testing, organization, CI integration, and thorough documentation, developers can ensure the efficiency and effectiveness of their test suites. As you unravel the world of Laravel testing, these best practices will serve as a guide to elevate your coding standards and contribute to the overall success of your Laravel projects.
0 notes
awsexchage · 7 years ago
Photo
Tumblr media
laravelでテストコードを書く前に設定しておいた方が良いこと https://ift.tt/2HqldhW
データベースのテストをする際には、テスト用のDBを用意して、そのDBでテストした方が良い。
理由
テストDBを用意して、テストを実行する際、 DatabaseMigrationsやDatabaseTransactionsを使ってもDBに全く影響を与えないわけでは無いです。
AUTO_INCREMENTの値など、一部は影響を受けてしまいます Laravel 5.4 で手軽にテストを書こう! | 株式会社インフィニットループ技術ブログ
実際に試してみました。
use DatabaseTransactions;が無い状態で、AUTO_INCREMENTのカラムがあるレコードを追加するコードのあるテストを実行(※以降テスト)
use DatabaseTransactions;がある状態テストを実行
use DatabaseTransactions;が無い状態テストを実行
そうするとAUTO_INCREMENTのカラムが連番にリませんでした。
テストをすることで少しでも本番DBなどに影響を与えてしまうのは良くないので、テストする時用でDBを切り替えてた方が良いと思いました。
データベースのテスト 5.4 Laravel
テストDBでのテスト方法
テスト用のDBを作成する。
hoge_testing ※surfixに _testingをつけるとテストDBだということが分かりやすい。
envファイルでDBを切り替えるパターン
開発環境、本番環境、ローカル環境などでテストDB名が違う場合は、このパターンを使うのが良いと思う。
テスト用のenvファイルを作る
ファイル名 .env.testing
DB名の箇所だけ書き換える
DB_DATABASE=hoge_testing
テストDBに対してmigrateを実行する方法
php artisan migrate --seed --env=testing
--env=testingをつけることで.env.testingのenvファイルを読んでmigrateを実行する事ができる。 Laravel5 で別環境(APP_ENV)で artisan コマンドを実行 – Qiita
テストコード内でmigrate:refreshなどを実行しているのであれば、コマンドでのmigrateの実行は不要かと思います。
phpunit.xmlでDBを切り替えるパターン
phpunit.xmlファイル内に<env name="DB_DATABASE" value="hoge_testing"/>を追加。 追加する箇所は以下の通りです。
<php> <env name="APP_ENV" value="testing"/> <env name="CACHE_DRIVER" value="array"/> <env name="SESSION_DRIVER" value="array"/> <env name="QUEUE_DRIVER" value="sync"/> <env name="DB_DATABASE" value="hoge_testing"/> </php>
https://qiita.com/colorrabbit/items/f660a4b6a2575b75a0e7
コマンドからmigrateを実行する場合
config/database.phpのmysqlの設定コピーして、databaseの箇所だけテストDBのDB名に書き換える。
'mysql_testing' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => 'hoge_testing', 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true, 'modes' => [ ], 'engine' => null, ],
後は以下のコマンドを実行すればテストDBに対してmigrate:refreshを実行することが出来る。
php artisan migrate:refresh --database=mysql_testing
https://qiita.com/colorrabbit/items/f660a4b6a2575b75a0e7
config をクリアする。
php artisan config:clear
このコマンドを実行せずにArtisan::call('migrate:refresh');など実行があるテストを実行したりすると、本番DBのデータが飛んだりするので要注意です。
DBの初期状態でデータベースのテストをする場合
テストクラスに以下メソッドを追加。
public function setUp() { parent::setUp(); Artisan::call('migrate:refresh'); Artisan::call('db:seed'); }
migrate:refreshを実行する際はmigrationファイルのdownメソッドにupメソッドが行った操作を元戻す処理 を書いておく必要があります。 https://readouble.com/laravel/5.3/ja/migrations.html
外部キー制約がある場合
以下のエラーが出る時があります。
SQLSTATE[23000]: Integrity constraint violation: 1217 Cannot delete or update a parent row: a foreign key constraint fails
以下の様にして一時的に外部キー制約を解除する。
public function down() { Schema::disableForeignKeyConstraints(); Schema::dropIfExists('user'); Schema::enableForeignKeyConstraints(); }
Laravel5でテスト時にtesting設定を使う方法 – アルファブレンド プログラミングチップス
laravelのバージョンが5.5であればRefreshDatabase;が使える。 use RefreshDatabase;を追加することで テスト前にMigrationとSeederが実行される。 LaravelでHTTPテスト – Qiita
テストを実行
‘phpunit’をコマンドで実行
おまけ
setUpBeforeClass以外の方法でクラスで一回だけ実行するメソッドを作る方法
migrate:refreshやdb:seedを、setUpメソッドに記述すると、テストにかかる時間が結構長くなってしまうので、クラスで一回だけ実行すれば場合はsetUpBeforeClassというメソッド内で実行すると良いようです。しかしsetUpBeforeClass内でenv()やlogger()などのlaravelで用意してくれているhelperは使えませんでした。 以下の様な処理がしたかったがenvが呼べない。
public static function setUpBeforeClass() { if(env('DB_DATABASE_TESTING') == 'hoge_testing'){ Artisan::call('migrate:refresh'); Artisan::call('db:seed'); self::insertTestData(); } }
なのでsetUpメソッドを一回のみ実行するようにしました。
private static $isSetup = false; public function setUp() { parent::setUp(); if(env('DB_DATABASE_TESTING') == 'hoge_testing' && self::$isSetup === false){ Artisan::call('migrate:refresh'); Artisan::call('db:seed'); self::$isSetup = true; } }
もっといい方法あるよって方は教えてください。
元記事はこちら
「laravelでテストコードを書く前に設定しておいた方が良いこと」
April 11, 2018 at 02:00PM
0 notes
fooyay · 8 years ago
Text
Returning to the BusinessTest
With some more advanced tools in place, it is time to revisit my efforts with the BusinessTest class.
The first thing to do is to add a factory for the Business model. Using the User factory as an example, I’m able to create a factory to create businesses for use in tests.
$factory->define(App\Business::class, function (Faker\Generator $faker) {    return [        'name' => $faker->company,        'zip_code' => $faker->postcode,        'active' => true,        'created_at' => Carbon::now(),        'updated_at' => Carbon::now(),    ]; });
This appears in ModelFactory.php. I looked over the schema for the table to confirm that each of the attributes is covered. I also added “use Carbon/Carbon;” at the top.
I then moved BusinessTest.php into the tests/integration/models directory. I added support for DatabaseTransactions as well, like in the UserTest.php file. Then I tried to write a test for the slug. This returned the following error: “InvalidArgumentException: Unable to locate factory with name [default] [App\Business].” Once again, Laravel is returning an obscure error. After chasing various red herrings related to namespaces, I started removing bits of the file until it looked more and more like UserTest.php. Ultimately, it turned out that with TestCase, the setup() function needs to call parent::setup(). It also needs special handling to deal with the database transactions.
I set that aside for now. Perhaps with the factories, the need for a setup() is no longer as important. So I removed the setup and continued.
/** @test */ function a_business_has_a_slug() {    $business = factory(Business::class)->create(['name' => 'Dan\'s 12 Amazing Donkeys & Donuts']);    $this->assertEquals('dans-12-amazing-donkeys-donuts', $business->slug()); }
Without setup() breaking things, this test passed green. The factory doesn’t set a value for slug, so I know that the model is doing the work here, as it should.
Next, I can test that hasEmployee($user) returns false when a company has no employees and $user is null.
function test_a_null_is_not_an_employee_in_a_business_with_no_employees() {    $nullUser = null;    $noEmployeesBusiness = factory(Business::class)->create();    $this->assertFalse($noEmployeesBusiness->hasEmployee($nullUser)); }
Again, setup is disabled here, so I created a business using the factory. This test passes.
To test the scenarios where a business has employees, I will need to create objects for User, Business, and Employee with the correct foreign keys, and that’s where I will turn my focus tomorrow.
0 notes