首頁 > 後端開發 > php教程 > 編寫高品質的測試

編寫高品質的測試

Susan Sarandon
發布: 2024-12-18 12:39:16
原創
286 人瀏覽過

Writing high quality tests

不幸的是,測試在許多組織中仍然沒有得到應有的關注。有時,如果開發人員沒有編寫任何測試,他們會感到內疚,同時測試程式碼往往沒有得到適當的審查。相反,評論中經常檢查的唯一事情是是否有任何測試,這是一種恥辱,因為僅僅進行測試還不夠好。實際上,它們至少應該與專案中的所有其他程式碼具有相同的質量,即使不是更高的品質。否則,測試確實可能會阻礙您,因為測試失敗的次數太多,難以理解,或者運行時間太長。我已經在關於使用記憶體中實作而不是儲存庫模擬的部落格文章中討論了其中的一些要點。現在我想討論一些其他的、更一般的、我在寫測試時要注意的事情。

極簡主義是關鍵

Stack Overflow 要求您為問題添加最少的、可重現的範例,在我看來,這對於出於完全相同的原因編寫測試也是非常好的建議。尤其是在編寫測試幾個月後閱讀測驗時,如果發生的事情較少,就更容易完全理解正在發生的事情。因此只編寫測試絕對必要的程式碼,並抵制僅僅因為這樣做很容易就添加更多內容的誘惑。但測試程式碼當然仍然必須完整,即測試應包含盡可能多的行,但盡可能少。

追求 100% 的程式碼覆蓋率

這可能是一個不受歡迎的觀點,但我認為以 100% 程式碼覆蓋率為目標是完全有意義的,儘管許多人似乎認為這是一種不好的做法。

有時團隊會選擇較低的值,例如程式碼覆蓋率達到 90%。然而,這對我來說沒有多大意義。首先,所有這些數字都有些隨意,很難使用資料進行備份。此外,在編寫新程式碼時,並非所有程式碼都需要經過測試才能通過該閾值。如果有人設法提高了覆蓋率,那麼下一個人可能根本不編寫任何測試,同時仍然保持高於 90% 的程式碼覆蓋率,這會導致錯誤的自信感。

我經常聽到的藉口之一是為 getter 和 setter 等簡單函數編寫測試沒有意義。也許令人驚訝的是,我完全同意這一點。但這裡有一個問題:如果沒有一個測試真正使用這些 getter 和 setter,那麼可能就沒有必要使用它們。 因此,與其抱怨實現 100% 測試覆蓋率有多麼困難,最好不要先編寫不需要的程式碼。這也避免了每行程式碼帶來的維護負擔。

但是,有一個小問題:有時程式碼會執行奇怪的操作,這可能會導致程式碼覆蓋工具將某些行標記為未覆蓋,即使它是在測試運行期間執行的。我沒有經常遇到這樣的情況,但如果沒有辦法使這項工作正常進行,我會將它們排除在程式碼覆蓋範圍之外。例如。 PHPUnit 允許使用他們的 codeCoverageIgnore 註解來做到這一點:

<?php

class SomeClass
{
    /**
     * @codeCoverageIgnore
     */
    public function doSomethingNotDetectedAsCovered()
    {

    }
}
登入後複製
登入後複製

這樣這個函數就不會被包含在程式碼覆蓋率分析中,這意味著仍然有可能達到 100% 的程式碼覆蓋率,而且我也會不斷檢查該值。另一種方法是選擇低於 100% 的值,但這樣會出現上面提到的相同問題:其他程式碼也可能不會被測試覆蓋,並且可能會被遺漏。

話雖如此,100% 的程式碼覆蓋率當然不能保證您的程式碼沒有任何錯誤。但是,如果您的應用程式程式碼中確實有未覆蓋的行,您甚至不會對測試進行更改以發現該行中的潛在錯誤。

寫出好的斷言

寫測試的原因是我們想要斷言程式碼的某種行為。因此斷言是測試中非常重要的一部分。

當然,編寫斷言時最重要的考慮因素是它正確地測試程式碼的行為。但緊隨其後的是程式碼失敗時斷言的行為方式。如果斷言由於某種原因失敗,那麼問題對於開發人員來說應該盡可能明顯。在此 Symfony 拉取請求中目前正在處理的情況就是這種情況顯而易見的情況。 Symfony 附帶了一個assertResponseStatusCodeSame 方法,它允許在功能測試中檢查回應的狀態碼:

<?php

declare(strict_types=1);

class LoginControllerTest extends WebTestCase
{
    public function testFormAttributes(): void
    {
        $client = static::createClient();

        $client->request('GET', '/login');
        $this->assertResponseStatusCodeSame(200);

        $this->assertSelectorCount(1, 'input[name="email"][required]');
    }
}
登入後複製
登入後複製

這個測試的​​問題是它在狀態碼不是 200 的情況下產生的輸出。由於測試通常在開發環境中運行,因此當訪問這個 URL 時 Symfony 將傳回一個錯誤頁面,並且assertResponseStatusCodeSame 方法將輸出斷言失敗時的完整回應。這個輸出非常長,因為它不僅返回 HTML,還返回 CSS 和 JavaScript,而且我的回滾緩衝區實際上太小,無法讓我閱讀整個訊息。

這絕對是我迄今為止遇到的最糟糕的例子,但如果程式碼中使用了錯誤的斷言,它也會很煩人。讓我們來看看上面的assertSelectorCount斷言的輸出,如果給定的選擇器沒有恰好產生一個元素,則該斷言會失敗並顯示以下訊息:

Failed asserting that the Crawler selector "input[name="email"][required]" was expected to be found 1 time(s) but was found 0 time(s).
登入後複製
登入後複製

它很好地了解了發生的問題。但是,斷言也可以用不同的方式編寫(不要在家裡這樣做!):

<?php

class SomeClass
{
    /**
     * @codeCoverageIgnore
     */
    public function doSomethingNotDetectedAsCovered()
    {

    }
}
登入後複製
登入後複製

有人可能會說這完全一樣,因此使用哪種變體並不重要。這與事實相差甚遠,因為如果電子郵件沒有單一必填輸入字段,則會出現以下訊息:

<?php

declare(strict_types=1);

class LoginControllerTest extends WebTestCase
{
    public function testFormAttributes(): void
    {
        $client = static::createClient();

        $client->request('GET', '/login');
        $this->assertResponseStatusCodeSame(200);

        $this->assertSelectorCount(1, 'input[name="email"][required]');
    }
}
登入後複製
登入後複製

這根本沒有幫助,無論誰致力於解決問題,首先都必須弄清楚問題到底是什麼。這表明,始終應該使用合適的斷言,並且 PHPUnit 附帶了許多適合所有類型用例的斷言。有時創建自訂斷言甚至是有意義的。

近年來我看到越來越流行的一個相對較新的斷言是快照測試。尤其是當開始從事前端專案時,它似乎有很大幫助。我過去經常將它與 React 一起使用。主要要點是您的測試看起來像這樣:

Failed asserting that the Crawler selector "input[name="email"][required]" was expected to be found 1 time(s) but was found 0 time(s).
登入後複製
登入後複製

神奇的事情發生在 toMatchSnapshot 方法中。在第一次運行時,它將樹變數的內容寫入單獨的檔案中。在後續運行中,它將樹值的新值與先前儲存在單獨檔案中的值進行比較。如果某些內容發生更改,它將導致測試失敗並顯示差異,並可以選擇再次更新快照,這意味著您可以立即修復測試。

雖然這聽起來確實不錯,但它也有一些缺點。首先,快照非常脆弱,因為每當元件的渲染標記發生變更時,測試就會失敗。其次,測試的意圖是隱藏的,因為它沒有解釋作者真正想要測試的內容。

但是,我真正喜歡它的是,每當我更改組件時,它都會提醒我使用該組件的所有其他組件,因為所有這些快照在下次運行時都會失敗。出於這個原因,我喜歡每個組件至少進行一次快照測試。

結論

總而言之,我認為您可以立即開始做一些事情來提高測試品質:

  • 將測試中的程式碼保持在絕對需要的最低限度
  • 目標是 100% 的程式碼覆蓋率,如果無法測試,請正確地將程式碼從程式碼覆蓋率機制中排除
  • 當測試失敗時,使用正確的斷言以獲得更好的錯誤訊息

在我看來,遵循這幾條規則已經會產生巨大的影響,並幫助您長時間享受在程式碼庫中工作!

以上是編寫高品質的測試的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板