首頁  >  文章  >  後端開發  >  Laravel教學:使用Stub解決單元測試中的依賴

Laravel教學:使用Stub解決單元測試中的依賴

巴扎黑
巴扎黑原創
2017-08-16 09:31:242077瀏覽


摘要:很早就知道有單元測試的概念,也曾嘗試過,慢慢地對單元測試和PHPUnit 的認識清晰了起來,也開始慢慢去實作單元測試。 Laravel 中的依賴我們都知道,Laravel 使用了 IoC,各個模組之間也因此解耦了。而正是因為這...

很早就知道有單元測試的概念,也曾嘗試過,慢慢地對單元測試和PHPUnit 的認識清晰了起來,也開始慢慢地去實踐單元測試。

Laravel 中的依賴

我們都知道,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 方法傳回與真正的回傳結構相同的值,而不需要依賴外部資料來源。

在Laravel 中使用樁件

我們透過 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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn