3 回答

TA貢獻1807條經驗 獲得超9個贊
盡管“只編寫功能測試”可能看起來像是一種逃避(“它們不是單元測試!”),但如果您不想陷入特定于框架的知識的困境,那么這是一個合理的建議。
您會看到,這是使用外觀、全局變量或靜態方法帶來的問題之一。為了使事情正常工作,各種各樣的事情都會在您的代碼(以及您的測試代碼)之外發生。
問題
要了解發生了什么,您首先需要了解 Laravel 如何利用容器和工廠將事物粘合在一起。
接下來,發生的事情是:
你的代碼(在某個地方
HomeController::home()
的調用中view()
。view()
調用以獲取創建視圖1app()
的工廠app()
來電Container::make
Container::make
呼叫Container::resolve
1Container::resolve
決定需要建造工廠并呼吁Container::build
這樣做最后
Container::build
(使用 PHP 的ReflectionClass發現\Illuminate\Contracts\View\Factory
無法實例化(因為它是一個接口)并觸發您看到的錯誤。
或者,如果您更像是一個視覺思考者:
觸發錯誤的原因是框架期望配置容器,以便抽象類(例如接口)已知具體類。
解決方案
現在我們知道發生了什么,并且我們想創建一個單元測試,我們能做什么?
一種解決方案可能似乎不使用view
.?只需自己注入 View 類即可!但如果您嘗試這樣做,您很快就會發現自己走上了一條基本上在用戶空間中重新創建大量框架代碼的道路。所以這不是一個好主意。
更好的解決方案是模擬view()
(現在它實際上是一個單元!)。但這仍然需要僅在測試代碼中重新創建框架代碼。還是不太好。[3]
最簡單的事情就是簡單地配置容器并告訴它使用哪個類。此時,您甚至可以模擬 View 類!
現在,純粹主義者可能會抱怨這還不夠“單元”,因為您的測試仍然會在被測代碼之外調用“真實”代碼,但我不同意......
你正在使用框架,所以使用框架!如果您的代碼使用框架提供的粘合,則測試反映此行為是有意義的。只要你不調用非粘合代碼,就沒有問題![4]
最后,為了讓您了解如何做到這一點,舉一個例子!
這個例子
假設您有一個看起來有點像這樣的控制器:
namespace App\Http\Controllers;
class HomeController extends \Illuminate\Routing\Controller
{
? ? public function home()
? ? {
? ? ? ? /* ... */
? ? ? ? return view('my.view');
? ? }
}
那么你的測試[5]可能看起來像這樣:
namespace Tests\Unit\app\Http\Controllers;
use App\Http\Controllers\HomeController;
use Illuminate\Contracts\View\Factory;
class HomeControllerTest extends \PHPUnit\Framework\TestCase
{
? ? public function testHome()
? ? {
? ? ? ? /*/ Arange /*/
? ? ? ? $mockFactory = $this->createMock(Factory::class);
? ? ? ? app()->instance(Factory::class, $mockFactory);
? ? ? ? /*/ Assert /*/
? ? ? ? $mockFactory->expects(self::once())
? ? ? ? ? ? ->method('make')
? ? ? ? ? ? ->with('my.view')
? ? ? ? ;
? ? ? ? /*/ Act /*/
? ? ? ? (new HomeController())->home();
? ? }
}
一個更復雜的示例是還創建一個模擬視圖并由模擬工廠返回它,但我將把它作為練習留給讀者。
腳注
app()
要求提供接口Illuminate\Contracts\View\Factory
,但沒有傳遞具體的類名除了調用另一個函數之外什么也不做的原因
Container::make
是方法名稱make
是由 PSR-11 定義的,并且 Laravel 容器是 PSR 兼容的。此外,Laravel 提供的功能測試邏輯已經為您完成了所有這些...
只是不要忘記用
@uses
所需的粘合來注釋測試,以避免在 PHPUnit 設置為有關“風險”測試的嚴格模式時發出警告。使用“安排、執行、斷言”模式的變體

TA貢獻1821條經驗 獲得超5個贊
這不是測試端點的方式 為了使測試正常工作,您應該擴展Laravel
。您應該實例化應用程序,因為它已經在項目中設置,TestCase.php
位于測試文件夾中的 , 。

TA貢獻1793條經驗 獲得超6個贊
如果您在《未來》中發現了這一點,并且看到了 @Pothcera 的文字墻,那么您需要了解以下內容:
他這樣做的唯一原因以及您在單元測試中首先看到這一點的唯一原因是因為他和您沒有在測試文件中從 更改PHPUnit\Framework\TestCase
為。Tests\TestCase
當您擴展包含app()
.
我的建議是簡單地擴展正確的基礎測試用例并繼續你的生活。
- 3 回答
- 0 關注
- 178 瀏覽
添加回答
舉報