Berikut ialah helaian tipu tentang cara menjadikan kelas perkhidmatan ringkas anda lebih berguna dengan menambahkan suntikan pergantungan, fasad dan cara menukar dengan mudah dengan palsu.
Rangkanya mudah:
Inilah kelas perkhidmatan asal kami yang kami mulakan (maaf kerana tidak mempunyai contoh yang menarik, tetapi tidak semestinya perlu mencipta satu untuk ini).
<?php namespace App\Foo; class FooService { public function foo(): string { return 'bar'; } public function fizz(): string { return 'buzz'; } }
Pertama, kami harus membuat kontrak supaya kami dapat memastikan bahawa perkhidmatan palsu kami dan perkhidmatan asal kami memenuhi jangkaan. Serta sebarang pelaksanaan masa hadapan.
<?php namespace App\Foo\Contracts; interface Foo { public function foo(): string; public function fizz(): string; }
Jangan lupa pastikan perkhidmatan melaksanakannya.
<?php namespace App; use App\Foo\Contracts\Foo; class FooService implements Foo { // ... }
Seterusnya, kami harus mengikat pelaksanaan konkrit dengan kontrak dalam pembekal perkhidmatan kami.
<?php namespace App\Providers; use App\Foo\Contracts\Foo; use App\FooService; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider { /** * Register any application services. */ public function register(): void { $this->app->bind(Foo::class, FooService::class); } // ... }
Kini, kami boleh mencipta kelas fasad kami.
<?php namespace App\Foo\Facades; use Illuminate\Support\Facades\Facade; /** * @method static string foo(): string * @method static string fizz(): string */ class Foo extends Facade { protected static function getFacadeAccessor(): string { return \App\Foo\Contracts\Foo::class; } }
Fasad hanya memerlukan nama pengikat yang akan ditarik dari bekas untuk dikembalikan daripada getFacadeAccessor. Dalam kes kami, itulah nama kontrak yang pada masa ini mempunyai perkhidmatan kami terikat kepadanya.
Perhatikan bahawa jika anda mahukan sokongan IDE, anda perlu mentakrifkan semula tandatangan kaedah dalam blok dokumen di atas kelas.
Pada ketika ini, kami boleh menggunakan fasad kami.
<?php namespace App\Http\Controllers; use App\Foo\Facades\Foo; class FooController extends Controller { public function index() { return response()->json([ 'foo' => Foo::foo(), ]); } }
Sebagai alternatif, kami juga boleh menyuntiknya sebagai pergantungan.
<?php namespace App\Http\Controllers; use App\Foo\Contracts; class FooController extends Controller { public function __construct(protected Foo $foo) {} public function index() { return response()->json([ 'foo' => $this->foo->foo(), ]); } }
Laravel sering menawarkan cara yang kemas untuk memalsukan fasadnya dengan mudah, mis. Acara::fake(). Kita boleh melaksanakannya sendiri.
Apa yang perlu kami lakukan ialah mencipta pelaksanaan kontrak kami yang palsu, kemudian tambahkan kaedah palsu pada fasad kami.
<?php namespace App\Foo; use App\Foo\Contracts\Foo; class FakeFooService implements Foo { public function __construct(public Foo $actual) {} public function foo(): string { return 'fake'; } public function fizz(): string { return 'very fake'; } }
Dalam pelaksanaan palsu kami, kami juga membuat rujukan awam kepada kelas konkrit "sebenar".
Dan inilah pelaksanaan palsu fasad kami. Anda boleh lihat kami menggunakan rujukan itu kepada sebenar.
<?php namespace App\Foo\Facades; use App\Foo\FakeFooService; use Illuminate\Support\Facades\Facade; /** * @method static string foo(): string * @method static string fizz(): string */ class Foo extends Facade { public static function fake() { $actual = static::isFake() ? static::getFacadeRoot()->actual : static::getFacadeRoot(); tap(new FakeFooService($actual), function ($fake) { static::swap($fake); }); } // ... }
Sekarang mari tulis ujian pantas yang sesuai dengan contoh pengawal yang kami buat di atas.
<?php namespace Tests\Feature; use App\Foo\Facades\Foo; use Illuminate\Testing\Fluent\AssertableJson; use Tests\TestCase; class FooTest extends TestCase { public function test_foo(): void { $response = $this->get('/'); $response->assertJson(fn (AssertableJson $json) => $json->where('foo', 'bar')); } public function test_fake_foo(): void { Foo::fake(); $response = $this->get('/'); $response->assertJson(fn (AssertableJson $json) => $json->where('foo', 'fake')); } }
Ujian tidak berguna tetapi ia menunjukkan betapa mudahnya untuk menggunakan palsu kami. Dalam test_fake_foo kita mendapat foo=fake manakala test_foo mengembalikan foo=bar.
Perkara yang menyeronokkan tentang palsu ialah dalam pelaksanaan palsu kami, kami boleh menambah kaedah tambahan untuk menguji apa sahaja yang kami rasa berguna. Sebagai contoh, kita boleh menampar pembilang dalam kaedah foo palsu kita yang meningkat setiap kali kita memanggil foo. Kemudian kita boleh menambah kaedah yang dipanggil assertFooCount di mana kita boleh menegaskan bahawa kaedah itu dipanggil seberapa banyak kali yang kita jangkakan.
<?php namespace App\Foo; use App\Foo\Contracts\Foo; use Illuminate\Testing\Assert; class FakeFooService implements Foo { public int $fooCount = 0; public function __construct(public Foo $actual) {} public function foo(): string { $this->fooCount++; return 'fake'; } public function fizz(): string { return 'very fake'; } public function assertFooCount(int $count) { Assert::assertSame($this->fooCount, $count); } }
Seperti yang anda lihat, kami menggunakan IlluminateTestingAssert Laravel untuk membuat penegasan. Kemudian ujian kami boleh kelihatan seperti ini.
public function test_incrementor(): void { Foo::fake(); Foo::foo(); Foo::foo(); Foo::foo(); Foo::assertFooCount(3); // pass! }
Itu sahaja!
Bukan semua perkara memerlukan fasad, tetapi apabila anda membina alatan/pakej yang digunakan secara dalaman, fasad selalunya merupakan corak yang kukuh untuk dipercayai.
Berikut ialah repo dengan semua kod: https://github.com/ClintWinter/laravel-facade-example
Atas ialah kandungan terperinci Mencipta Fasad Boleh Diuji dalam Laravel. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!