Repository
用 Repository 包裝 Model
- 不讓 Controller 直接接觸 Model
- 避免 Controller 肥大
- 封裝資料存取邏輯
- 抽換資料庫實作較容易
建立 app/Repositories/ArticleRepository.php
:
namespace App\Repositories;
use App\Article;
class ArticleRepository
{
}
這就是我們要測試的目標。
再建立 tests/ArticleRepositoryTest.php
測試類別:
use App\Repositories\ArticleRepository;
// 一樣要先繼承
class ArticleRepositoryTest extends TestCase
{
/**
* @var ArticleRepository
*/
protected $repository = null;
/**
* 建立 100 筆假文章
*/
protected function seedData()
{
for ($i = 1; $i <= 100; $i ++) {
Article::create([
'title' => 'title ' . $i,
'body' => 'body ' . $i,
]);
}
}
// 跟前面一樣,每次都要初始化資料庫並重新建立待測試物件
// 以免被其他 test case 影響測試結果
public function setUp()
{
parent::setUp();
$this->initDatabase();
$this->seedData();
// 建立要測試用的 repository
$this->repository = new ArticleRepository();
}
public function tearDown()
{
$this->resetDatabase();
$this->repository = null;
}
}
測試 latest10
方法:
public function testFetchLatest10Articles()
{
// 從 repository 中取得最新 10 筆文章
$articles = $this->repository->latest10();
$this->assertEquals(10, count($articles));
// 確認標題是從 100 .. 91 倒數
// "title 100" .. "title 91"
$i = 100;
foreach ($articles as $article) {
$this->assertEquals('title ' . $i, $article->title);
$i -= 1;
}
}
執行測試出現 Fatal error
,因為我們還沒有 latest10
方法。
在 app/Repositories/ArticleRepository.php
加入:
public function latest10()
{
}
執行測試後紅燈,但錯誤訊息不同了,這是正常的第一步,我們還需要加入實作:
public function latest10()
{
return Article::query()->orderBy('id', 'desc')->limit(10)->get();
}
測試出現綠燈,成功。
這就是 TDD 的流程,也就是「寫測試 → 紅燈 → 寫程式 → 綠燈」。
接下來都會照這個步調來進行。
測試 create
方法:
class ArticleRepositoryTest extends TestCase
{
// ...
public function testCreateArticle()
{
// 因為前面有 100 筆了,
// 所以這裡我們可以預測新增後的 id 是 101
$latestId = self::POST_COUNT + 1;
$article = $this->repositorys->create([
'title' => 'title ' . $latestId,
'body' => 'body ' . $latestId,
]);
$this->assertEquals(self::POST_COUNT + 1, $article->id);
}
}
測試失敗,新增 ArticleRepository::create
方法:
public function create(array $attributes)
{
return Article::create($attributes);
}
測試成功。