練習 - 修正失敗的測試
此時,您可以在透過組建管線移動變更時,執行單元測試。 您也可以使用方法來測量測試所涵蓋的程式碼數量。
最好一律在本機執行測試,再將變更提交至管線。 但是當有人忘記並提交中斷組建的變更時,會發生什麼事?
在此單元中,您將會修正因失敗單元測試所造成的中斷組建。 在這裡,您將會:
- 從 GitHub 取得起始程式碼。
- 將程式碼涵蓋範圍新增至您的專案。
- 將程式碼推送到您的存放庫。
- 觀看管線自動執行和單元測試失敗。
- 在本機重現失敗。
- 分析並修正失敗。
- 推送修正程式,並觀看組建成功。
檢閱新的單元測試
小組的最新功能只涵蓋排行榜。 我們需要從資料庫取得分數,因此,我們可以撰寫單元測試來驗證 IDocumentDBRepository<T>.GetItemsAsync
方法。
測試看起來像這樣。 您還不需要新增任何程式碼。
[TestCase(0, ExpectedResult=0)]
[TestCase(1, ExpectedResult=1)]
[TestCase(10, ExpectedResult=10)]
public int ReturnRequestedCount(int count)
{
const int PAGE = 0; // take the first page of results
// Fetch the scores.
Task<IEnumerable<Score>> scoresTask = _scoreRepository.GetItemsAsync(
score => true, // return all scores
score => 1, // we don't care about the order
PAGE,
count // fetch this number of results
);
IEnumerable<Score> scores = scoresTask.Result;
// Verify that we received the specified number of items.
return scores.Count();
}
回想一下,在 NUnit 測試中,TestCase
提供要用來測試該方法的內嵌資料。 NUnit 會呼叫 ReturnRequestedCount
單元測試方法,如下所示:
ReturnRequestedCount(0);
ReturnRequestedCount(1);
ReturnRequestedCount(10);
此測試也會使用 ExpectedResult
屬性來簡化測試程式碼,並協助清除其意圖。 NUnit 會自動比較傳回值與這個屬性的值,而不需明確地呼叫判斷提示。
我們會選擇數個值來表示一般查詢。 我們也會納入 0,以涵蓋該邊緣案例。
從 GitHub 擷取分支
如同您先前所執行的,從 GitHub 擷取 failed-test
分支,並簽出 (或切換至) 該分支。
在 Visual Studio Code 中,開啟整合式終端。
執行下列
git fetch
和git checkout
命令,以從 Microsoft 存放庫下載名為failed-test
的分支,並切換至該分支:git fetch upstream failed-test git checkout -B failed-test upstream/failed-test
我們會將分支命名為
failed-test
,以方便學習。 實務上,您會按照分支目的或功能為分支命名。執行下列命令以建立本機工具資訊清單檔、安裝
ReportGenerator
工具,以及新增coverlet.msbuild
套件至您的測試專案:dotnet new tool-manifest dotnet tool install dotnet-reportgenerator-globaltool dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
您需要此步驟,因為
failed-test
分支未包含您新增至unit-tests
分支的工作。將您的測試專案檔和工具資訊清單檔新增至暫存索引,並認可您的變更。
git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj git add .config/dotnet-tools.json git commit -m "Configure code coverage tests"
執行下列
git push
命令,以將failed-test
分支上傳至您的 GitHub 存放庫:git push origin failed-test
查看管線中的測試失敗
假設您最後並未再次執行測試,就匆促地將工作向上推送。 幸運的是,管線可協助我們在進行單元測試時及早揪出問題。 您將在這裡看到該問題。
從 Azure Pipelines 中,在組建透過管線執行時進行追蹤。
在其執行時,展開 [執行單元測試 - 版本] 工作。
您會看到
ReturnRequestedCount
測試方法失敗。當輸入值為 0 時測試即會通過,但當輸入值為 1 或 10 時就會失敗。
只有在上一個工作成功時,才會將組建發佈到管線中。 在這裡,組建因為單元測試失敗而未發佈。 這會防止其他人不小心取得中斷的組建。
實務上,您永遠都不會在組建執行時手動追蹤它們。 以下提供您可能用來探索失敗的數種方式:
來自 Azure DevOps 的電子郵件通知
您可以設定 Azure DevOps 在組建完成時傳送電子郵件通知給您。 當建置會失敗時,主旨列的開頭為「[組建失敗]」。
Azure Test Plans
在 Azure DevOps 中,選取 [測試計畫],然後選取 [執行]。 您會看到最新的測試回合,包括剛執行的測試回合。 選取最新完成的測試。 您會看到八個測試中有兩個失敗。
儀表板
在 Azure DevOps 中,選取 [總覽],然後選取 [儀表板]。 您會看到失敗出現在 [測試結果趨勢] Widget 中。 [程式碼涵蓋範圍] 小工具為空白,表示程式碼涵蓋範圍並未執行。
組建徽章
雖然
failed-test
分支未在 README.md 中包含組建徽章,但以下是當組建失敗時您會在 GitHub 上看到的內容:
分析測試失敗
當單元測試失敗時,視失敗的本質而定,您通常會有兩個選擇:
- 如果測試顯示程式碼中的瑕疵,則修正程式碼並重新執行測試。
- 如果功能已變更,請調整測試以符合新的需求。
在本機重現失敗。
在本節中,您將在本機重現失敗。
在 Visual Studio Code 中,開啟整合式終端。
從終端機中,執行此
dotnet build
命令來建置應用程式:dotnet build --configuration Release
從終端機中,執行此
dotnet test
命令來執行單元測試:dotnet test --no-build --configuration Release
您應該會看到如同您在管線中所見的相同錯誤。 以下是部分輸出:
Starting test execution, please wait... A total of 1 test files matched the specified pattern. Failed ReturnRequestedCount(1) [33 ms] Error Message: Expected: 1 But was: 0 Stack Trace: at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context) at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0() at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action) Failed ReturnRequestedCount(10) [1 ms] Error Message: Expected: 10 But was: 9 Stack Trace: at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context) at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0() at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action) Failed! - Failed: 2, Passed: 6, Skipped: 0, Total: 8, Duration: 98 ms
尋找錯誤的原因
您注意到每個失敗的測試都會產生差一的結果。 例如,預期 10 時,測試便會傳回 9。
查看所要測試方法 LocalDocumentDBRepository<T>.GetItemsAsync
的原始程式碼。 您應該會看到以下內容:
public Task<IEnumerable<T>> GetItemsAsync(
Func<T, bool> queryPredicate,
Func<T, int> orderDescendingPredicate,
int page = 1, int pageSize = 10
)
{
var result = _items
.Where(queryPredicate) // filter
.OrderByDescending(orderDescendingPredicate) // sort
.Skip(page * pageSize) // find page
.Take(pageSize - 1); // take items
return Task<IEnumerable<T>>.FromResult(result);
}
在此案例中,您可以檢查 GitHub,以查看檔案最近是否變更。
您懷疑 pageSize - 1
所傳回的結果數目少了一個,而這應該只是 pageSize
。 在我們的案例中,這是您推送工作而不進行測試時所犯的錯誤,但在真實案例中,您可以洽詢在 GitHub 上變更檔案的開發人員,以判斷變更的原因。
提示
討論與共同作業也可能會在 GitHub 上發生。 您可以在提取要求上加上註解,或提出問題。
修正錯誤
在本節中,您會藉由將程式碼變更回其原始狀態,並執行測試以確認修正來修正此錯誤。
從 Visual Studio Code,在檔案總管中開啟 Tailspin.SpaceGame.Web/LocalDocumentDBRepository.cs。
修改
GetItemsAsync
方法如下所示:public Task<IEnumerable<T>> GetItemsAsync( Func<T, bool> queryPredicate, Func<T, int> orderDescendingPredicate, int page = 1, int pageSize = 10 ) { var result = _items .Where(queryPredicate) // filter .OrderByDescending(orderDescendingPredicate) // sort .Skip(page * pageSize) // find page .Take(pageSize); // take items return Task<IEnumerable<T>>.FromResult(result); }
此版本會將
pageSize - 1
變更為pageSize
。儲存檔案。
在整合式終端機中,建置應用程式。
dotnet build --configuration Release
您應該會看到組建成功。
在實務上,您可以執行應用程式並短暫地試用。基於學習目的,我們現在會略過該程式。
在終端機中,執行單元測試。
dotnet test --no-build --configuration Release
您會看到所有測試通過。
Starting test execution, please wait... A total of 1 test files matched the specified pattern. Passed! - Failed: 0, Passed: 8, Skipped: 0, Total: 8, Duration: 69 ms
在整合式終端機中,將每個修改的檔案新增至索引、認可變更,然後將分支推送至 GitHub。
git add . git commit -m "Return correct number of items" git push origin failed-test
提示
在此
git add
範例中的點 (.
) 是萬用字元。 其會比對目前目錄和所有子目錄中的所有取消暫存檔案。使用這個萬用字元之前,最好在認可之前先執行
git status
以確定您正在暫存您要暫存的檔案。返回至 Azure Pipelines。 觀看變更在管線中移動。 測試會通過,而整體組建會成功。
(選擇性) 若要驗證測試結果,您可以在組建完成時,選取 [測試] 和 [程式碼涵蓋範圍] 索引標籤。
您也可以查看儀表板,以檢視更新的結果趨勢。
太棒了! 您已修正組建。 接下來,您將會了解如何清除 Azure DevOps 環境。