摘要:很早就知道有單元測試的概念,也曾嘗試過,慢慢地對單元測試和PHPUnit 的認識清晰了起來,也開始慢慢去實作單元測試。 Laravel 中的依賴我們都知道,Laravel 使用了 IoC,各個模組之間也因此解耦了。而正是因為這...
很早就知道有單元測試的概念,也曾嘗試過,慢慢地對單元測試和PHPUnit 的認識清晰了起來,也開始慢慢地去實踐單元測試。
我們都知道,Laravel 使用了 IoC,各個模組之間也因此解耦了。而正是因為這一點,我們在 Laravel 中編寫單元測試的時候,變得更加輕鬆了。
考慮以下場景。我們在開發中,可能會在控制器和模型之間加一個 Repository
來處理資料。那我們的 Controller
就會依賴 Respository
。利用 Laravel 的 IoC,我們可以定義一個 Service Provider
來集中將 Respository
注入到容器中。
假設我們現在有這樣一個 Repository,裡面記錄了商品的信息,我們想要在 Controller 中獲取某件商品信息,然後執行一些業務邏輯。
Class GoodRepository{ public function getGoodById($goodId) { // TODO: Get good by its id. } }class GoodController extends Controller{ public function show($id, GoodRepository $goodRepository) { // TODO: Do something with good info from that repository. } }// In route/api.phpRoute::get('/api/good/{id}', 'GoodController@show');// Create a RepositoriesServiceProvider in Provider/RepositoriesServiceProvider.php。// And inject the GoodRepository into Container.class RepositoriesServiceProvider extends ServiceProvider{ public function boot() { } public function register() { $this->app->singleton(GoodRepository::class); } }
好了,我們可以發現,GoodController
是依賴 GoodRepository
的,而 GoodRepository
是依賴資料庫中的資料的。可是我們在做單元測試的時候,希望盡可能少的產生依賴。所以,我們應該希望能夠掌控 GoodRepository
所回傳的資料。
在 Laravel,提供了 $this->get('/path/to/route');
的方法來對 HTTP 請求進行測試。這個測試必然會牽涉到剛才所提到的那些依賴,如何解決這個依賴的問題,我們可以請出我們的主角────樁件。
將物件替換為(可選地)傳回配置好的回傳值的測試替身的實踐方法稱為上樁(stubbing)。
這是 PHPUnit 文檔上 的解釋。那我的理解呢,所謂的樁件,就是模擬一個依賴的類的行為,使得這個行為所做的事情在我們自己的掌控之中。例如上面的這種情況,我們希望模擬 GoodRepository
的 getGoodById
方法傳回與真正的回傳結構相同的值,而不需要依賴外部資料來源。
我們透過 Service Provider
註冊了 GoodRepository
單例,那麼按照這個思路,我們在寫單元測試的時候,就可以將我們定義的樁件,註冊為 GoodRepository
單例。
class GoodControllerTest extends TestCase{ public function testShow() { $data = []; // The data returns from GoodRepository::getGoodById. $stub = $this->createMock(GoodRepository::class); $stub->method('getGoodById')->will($this->returnValue($data)); $this->app->singleton(GoodRepository::class, function () use ($stub) { return $stub; }); $response = $this->get('/api/good/1'); // Some assertions. } }
我们通过在这里将桩件 $stub
用单例模式注册给了 Container
,在调用 $this->get('/api/good/1');
时原本在 Controller
中的 GoodRepository
依赖就变成了我们自定义的桩件 $stub
。我们将 $data
定义为和返回值相同的结构,注册到桩件中。这样,所有的数据都在我们可控的范围了。
如果我们在这里不使用桩件,而是直接依赖外部(数据库)中的数据,那么如果 id 为 1 的数据被删除了,我们是不是就要改成 2 了呢?我们是不是就要重新计算数据了匹配断言了呢?这样的测试,可靠性便大大降低。
任何一個可靠的系統,單元測試都是不可或缺的。慶幸的是,PHPUnit 幫我們提供了好用的單元測試。本文所講的,也只是 PHPUnit 的九牛一毛。而我自己也在慢慢摸索慢慢實踐中。與君共勉。
以上是Laravel教學:使用Stub解決單元測試中的依賴的詳細內容。更多資訊請關注PHP中文網其他相關文章!