雖然並非每個人都在這樣做,但測試你的應用程序是作為開發人員最基本的部分之一。單元測試是最常見的測試。通過單元測試,你可以檢查一個類是否完全按照你的預期那樣運行。有時,你在你的應用程序中使用的是第三方服務,很難設置好所有內容來進行單元測試。這正是模擬發揮作用的時候。
關鍵要點
- 模擬是創建一個替代單元測試中真實對象的替代對象的過程,這在測試嚴重依賴依賴注入的應用程序時特別有用。
- Mockery 是 Pádraic Brady 創建的一個庫,可用於模擬單元測試中的對象,為 PHPUnit 的默認模擬功能提供了一種替代方案。
- Mockery 允許開發人員定義對方法調用次數、將接收的參數以及將返回的值的期望,使其成為隔離單元測試中依賴項的強大工具。
- 雖然 PHPUnit 已經可以模擬對象,但 Mockery 為希望確保其單元測試不受其他類影響的開發人員提供了更大的靈活性和便利性。
什麼是模擬?
模擬對像只不過是創建一個替代對象,它在單元測試中替換真實對象。如果你的應用程序嚴重依賴依賴注入,模擬是可行的方法。
模擬對象可能有幾個原因:
- 執行單元測試時,最好隔離類。你不想讓另一個類或服務干擾你的單元測試。
- 對象尚不存在。你可以先創建測試,然後構建最終對象。
- 模擬對象通常比為測試準備整個數據庫更快。
運行單元測試時,你可能正在使用 PHPUnit。 PHPUnit 帶有一些默認的模擬功能,如文檔中所示。你可以在 Jeune Asuncion 撰寫的這篇文章中閱讀更多關於模擬的常規信息以及 PHPUnit 的模擬功能。
在本文中,我們將深入探討由 Pádraic Brady 創建的庫 Mockery。我們將創建一個溫度類,該類將注入當前不存在的天氣服務。
設置
讓我們從設置項目開始。我們從包含以下內容的 composer.json 文件開始。這將確保我們擁有 mockery 和 PHPUnit。
<code>{ "name": "sitepoint/weather", "license": "MIT", "type": "project", "require": { "php": ">=5.3.3" }, "autoload": { "psr-0": { "": "src/" } }, "require-dev": { "phpunit/phpunit": "4.1.*", "mockery/mockery": "0.9.*" } }</code>
我們還創建一個名為 phpunit.xml 的 PHPUnit 配置文件
<phpunit> <testsuite name="SitePoint Weather"> <directory>./tests</directory> </testsuite> <listeners> <listener class="\Mockery\Adapter\Phpunit\TestListener" file="vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/TestListener.php"/> </listeners> </phpunit>
定義這個監聽器很重要。如果沒有監聽器,如果方法 once()
、twice()
和 times()
使用不正確,則不會引發錯誤。稍後將詳細介紹。
我還創建了 2 個目錄。 src 目錄用於保存我的類,tests 目錄用於存儲我們的測試。在 src 目錄中,我創建了路徑 SitePointWeather。
我們首先創建 WeatherServiceInterface。我們不存在的天氣服務將實現此接口。在這種情況下,我們只提供一個方法,該方法將為我們提供攝氏溫度。
<code>{ "name": "sitepoint/weather", "license": "MIT", "type": "project", "require": { "php": ">=5.3.3" }, "autoload": { "psr-0": { "": "src/" } }, "require-dev": { "phpunit/phpunit": "4.1.*", "mockery/mockery": "0.9.*" } }</code>
因此,我們有一個服務可以為我們提供攝氏溫度。我想獲得華氏溫度。為此,我創建了一個名為 TemperatureService 的新類。此服務將注入天氣服務。除此之外,我們還定義了一個方法,該方法將攝氏溫度轉換為華氏溫度。
<phpunit> <testsuite name="SitePoint Weather"> <directory>./tests</directory> </testsuite> <listeners> <listener class="\Mockery\Adapter\Phpunit\TestListener" file="vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/TestListener.php"/> </listeners> </phpunit>
創建單元測試
我們已經準備好設置單元測試了。我們在 tests 目錄中創建一個 TemperatureServiceTest 類。在這個類中,我們創建方法 testGetTempFahrenheit()
,它將測試我們的華氏方法。
此方法中要做的第一步是創建一個新的 TemperatureService 對象。就在我們這樣做的時候,我們的構造函數將請求一個實現了 WeatherServiceInterface 的對象。由於我們還沒有這樣的對象(我們也不想要),我們將使用 Mockery 為我們創建一個模擬對象。讓我們看看完成後的方法是什麼樣的。
namespace SitePoint\Weather; interface WeatherServiceInterface { /** * 返回摄氏温度 * * @return float */ public function getTempCelsius(); }
我們首先創建模擬對象。我們告訴 Mockery 我們想要模擬哪個對象(或接口)。第二步是描述將在此模擬對像上調用的方法。在 shouldReceive()
方法中,我們定義將調用的方法的名稱。
我們定義此方法將調用的次數。我們可以使用 once()
、twice()
和 times(X)
。在這種情況下,我們預計它只會調用一次。如果未調用或調用次數過多,單元測試將失敗。
最後,我們在 andReturn()
方法中定義將返回的值。在這種情況下,我們返回 25。 Mockery 還具有 andReturnNull()
、andReturnSelf()
和 andReturnUndefined()
等返回方法。如果這是你的預期,Mockery 也能夠拋出異常。
我們現在有了模擬對象,可以創建我們的 TemperatureService 對象並像往常一樣進行測試。 25 攝氏度是 77 華氏度,因此我們檢查是否從我們的 getTempFahrenheit()
方法中收到 77。
如果你在你的根目錄中運行 vendor/bin/phpunit tests/
,你將從 PHPUnit 獲得綠燈,表明一切都很完美。
高級用法
上面的例子相當簡單。沒有參數,只是一個簡單的調用。讓我們讓事情變得複雜一些。
假設我們的天氣服務還有一個方法可以在確切的小時獲取溫度。我們將以下方法添加到我們當前的 WeatherServiceInterface。
namespace SitePoint\Weather; class TemperatureService { /** * @var WeatherServiceInterace $weatherService 保存天气服务 */ private $weatherService; /** * 构造函数。 * * @param WeatherServiceInterface $weatherService */ public function __construct(WeatherServiceInterface $weatherService) { $this->weatherService = $weatherService; } /** * 获取当前华氏温度 * * @return float */ public function getTempFahrenheit() { return ($this->weatherService->getTempCelsius() * 1.8000) + 32; } }
我們想知道,晚上 0:00 到 6:00 之間的平均溫度是多少。為此,我們在 TemperatureService 中創建一個新方法來計算平均溫度。為此,我們從 WeatherService 中檢索 7 個溫度併計算平均值。
<code>{ "name": "sitepoint/weather", "license": "MIT", "type": "project", "require": { "php": ">=5.3.3" }, "autoload": { "psr-0": { "": "src/" } }, "require-dev": { "phpunit/phpunit": "4.1.*", "mockery/mockery": "0.9.*" } }</code>
讓我們看看我們的測試方法。
<phpunit> <testsuite name="SitePoint Weather"> <directory>./tests</directory> </testsuite> <listeners> <listener class="\Mockery\Adapter\Phpunit\TestListener" file="vendor/mockery/mockery/library/Mockery/Adapter/Phpunit/TestListener.php"/> </listeners> </phpunit>
我們再次模擬接口,並定義將調用的方法。接下來,我們定義此方法將調用的次數。我們在前面的示例中使用了 once()
,現在我們使用 times(7)
來指示我們期望此方法被調用 7 次。如果該方法沒有被精確調用 7 次,則測試將失敗。如果你沒有在 phpunit.xml 配置文件中定義監聽器,你將不會收到關於此的通知。
接下來,我們定義 with()
方法。在 with
方法中,你可以定義你期望的參數。在這種情況下,我們期望 7 個不同的小時。
最後,我們有 andReturn()
方法。在這種情況下,我們指示了 7 個返回值。如果你定義的返回值較少,則每次都會重複最後一個可用的返回值。
當然,Mockery 可以做更多的事情。有關完整的指南和文檔,我建議你查看 Github 頁面。
如果你對上面項目的代碼感興趣,你可以查看這個 Github 頁面。
結論
使用 PHPUnit,你已經可以模擬對象了。但是,你也可以像上面示例中解釋的那樣使用 Mockery。如果你正在對你的類進行單元測試,並且你不想讓任何其他類影響你的測試,mockery 可以輕鬆地幫助你。如果你真的想進行功能測試,最好看看你是否可以集成真正的測試。你目前是否正在使用 PHPUnit 模擬並考慮切換到 Mockery?你想在後續文章中看到更多更大的 Mockery 示例嗎?請在下面的評論中告訴我。
關於 Mockery 和測試依賴項的常見問題解答 (FAQ)
什麼是 Mockery,為什麼它在 PHP 測試中很重要?
Mockery 是一個強大而靈活的 PHP 模擬對象框架,用於單元測試。它被設計為 PHPUnit 模擬對像功能的直接替代品。 Mockery 允許開發人員隔離被測代碼並創建測試替身,這些測試替身模擬複雜對象的行為。這在單元測試中至關重要,因為它確保被測代碼不依賴於任何外部因素或狀態。
如何在我的 PHP 項目中安裝和設置 Mockery?
要安裝 Mockery,你需要擁有 Composer,這是一個 PHP 的依賴項管理器。你可以通過運行命令 composer require --dev mockery/mockery
來安裝 Mockery。安裝後,你可以在測試文件中通過在測試拆卸方法中調用 Mockery::close()
來設置 Mockery,以清理模擬對象。
如何使用 Mockery 創建模擬對象?
在 Mockery 中創建模擬對像很簡單。你可以使用 mock()
方法來創建一個模擬對象。例如,$mock = Mockery::mock('MyClass');
將創建一個 MyClass 的模擬對象。
如何在 Mockery 中定義期望?
在 Mockery 中,你通過將方法鏈接到模擬對象來定義期望。例如,$mock->shouldReceive('myMethod')->once()->andReturn('mocked value');
此代碼告訴 Mockery 預期“myMethod”將被調用一次,並且應該返回“mocked value”。
Mockery 中模擬和存根的區別是什麼?
在 Mockery 中,模擬是我們可以在其上設置期望的對象,而存根是預先編程了響應的模擬對象。當響應是唯一重要的事情時,通常使用存根,而當測試交互本身時,則使用模擬。
如何使用 Mockery 測試私有方法?
不建議直接測試私有方法,因為它違反了封裝原則。但是,如果需要,你可以使用 Mockery 中的 shouldAllowMockingProtectedMethods()
方法來允許模擬受保護和私有方法。
如何在 Mockery 中處理構造函數參數?
如果要模擬的類具有帶參數的構造函數,可以將它們作為數組傳遞給 mock()
方法。例如,$mock = Mockery::mock('MyClass', [$arg1, $arg2]);
將將 $arg1 和 $arg2 傳遞給 MyClass 的構造函數。
如何使用 Mockery 模擬靜態方法?
Mockery 提供了一種使用 alias:
前綴模擬靜態方法的方法。例如,$mock = Mockery::mock('alias:MyClass');
將創建一個可以用來對 MyClass 的靜態方法設置期望的模擬對象。
如何驗證 Mockery 中是否已滿足所有期望?
你可以在測試拆卸方法中使用 Mockery::close()
方法來驗證是否已滿足所有期望。如果任何期望未滿足,Mockery 將引發異常。
如何在 Mockery 中處理異常?
你可以使用 andThrow()
方法設置模擬對像以拋出異常。例如,$mock->shouldReceive('myMethod')->andThrow(new Exception);
將在調用“myMethod”時拋出異常。
以上是用嘲笑嘲笑您的測試依賴性的詳細內容。更多資訊請關注PHP中文網其他相關文章!

要保護應用免受與會話相關的XSS攻擊,需採取以下措施:1.設置HttpOnly和Secure標誌保護會話cookie。 2.對所有用戶輸入進行輸出編碼。 3.實施內容安全策略(CSP)限制腳本來源。通過這些策略,可以有效防護會話相關的XSS攻擊,確保用戶數據安全。

优化PHP会话性能的方法包括:1.延迟会话启动,2.使用数据库存储会话,3.压缩会话数据,4.管理会话生命周期,5.实现会话共享。这些策略能显著提升应用在高并发环境下的效率。

theSession.gc_maxlifetimesettinginphpdeterminesthelifespanofsessiondata,setInSeconds.1)它'sconfiguredinphp.iniorviaini_set().2)abalanceisesneededeededeedeedeededto toavoidperformance andunununununexpectedLogOgouts.3)

在PHP中,可以使用session_name()函數配置會話名稱。具體步驟如下:1.使用session_name()函數設置會話名稱,例如session_name("my_session")。 2.在設置會話名稱後,調用session_start()啟動會話。配置會話名稱可以避免多應用間的會話數據衝突,並增強安全性,但需注意會話名稱的唯一性、安全性、長度和設置時機。

會話ID應在登錄時、敏感操作前和每30分鐘定期重新生成。 1.登錄時重新生成會話ID可防會話固定攻擊。 2.敏感操作前重新生成提高安全性。 3.定期重新生成降低長期利用風險,但需權衡用戶體驗。

在PHP中設置會話cookie參數可以通過session_set_cookie_params()函數實現。 1)使用該函數設置參數,如過期時間、路徑、域名、安全標誌等;2)調用session_start()使參數生效;3)根據需求動態調整參數,如用戶登錄狀態;4)注意設置secure和httponly標誌以提升安全性。

在PHP中使用會話的主要目的是維護用戶在不同頁面之間的狀態。 1)會話通過session_start()函數啟動,創建唯一會話ID並存儲在用戶cookie中。 2)會話數據保存在服務器上,允許在不同請求間傳遞數據,如登錄狀態和購物車內容。

如何在子域名間共享會話?通過設置通用域名的會話cookie實現。 1.在服務器端設置會話cookie的域為.example.com。 2.選擇合適的會話存儲方式,如內存、數據庫或分佈式緩存。 3.通過cookie傳遞會話ID,服務器根據ID檢索和更新會話數據。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

Atom編輯器mac版下載
最受歡迎的的開源編輯器

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。