訓練
模組
Visual Studio 中的 C# 測試 - Training
使用 Visual Studio 中的測試工具來開始測試 C# 應用程式。 了解如何撰寫測試、使用測試總管、建立測試套件,以及套用紅色、綠色、重構模式來撰寫程式碼。
重要
Visual Studio App Center 已排定於 2025 年 3 月 31 日淘汰。 雖然您可以繼續使用 Visual Studio App Center,直到它完全淘汰為止,但有數個建議您考慮移轉至的建議替代方案。
Xamarin.UITest 是 C# 測試架構,使用 NUnit 進行 iOS 和 Android 應用程式的 UI 接受測試。 它與 Xamarin.iOS 和 Xamarin.Android 項目緊密整合,但也可以與原生 iOS 和 Android 專案搭配使用。 Xamarin.UITest 是自動化連結 庫 ,可讓 NUnit 測試在 Android 和 iOS 裝置上執行。 測試會以使用者身分與使用者介面互動:輸入文字、點選按鈕和手勢,例如撥動。
一般而言,每個 Xamarin.UITest 都會撰寫為稱為 [Test]
的方法。 包含測試類別稱為 [TestFixture]
。 測試裝置包含單一測試或測試群組。 裝置也負責設定,讓測試回合和清除完成測試時必須完成。 每個測試都應該遵循 Arrange-Act-Assert 模式:
開始使用 Xamarin.UITest 的最佳時機是在開發行動應用程式期間。 自動化測試是以功能的形式撰寫,是根據下列清單中所述的步驟進行開發:
對於不再處於使用中開發狀態的現有應用程式,回溯新增自動化測試可能不符合成本效益。 相反地,更好的方法是在修正 Bug 時使用 Xamarin.UITest。 例如,請考慮沒有自動化測試的應用程式,而使用者回報錯誤。 指派修正 Bug 的開發人員可能會採取下列動作的一些 (或所有) :
自動化UI測試高度依賴在畫面上尋找和互動檢視。 Xamarin.UITest 可透過兩組重要的 API 來解決此需求,這些 API 彼此搭配使用:
為了協助撰寫測試,Xamarin.UITest 提供 read-eval-print-loop (REPL) 。 REPL 可讓開發人員和測試人員在執行應用程式時與畫面互動,並簡化建立查詢。
所有與行動應用程式的測試互動都會透過的 Xamarin.UITest.IApp
實例進行。 此介面會定義測試與應用程式共同作業並與使用者介面互動的重要方法。 此介面有兩個具體實作:
Xamarin.UITest.iOS.iOSApp
此類別會將 iOS 的測試自動化。Xamarin.UITest.Android.AndroidApp
此類別適用於在Android上自動化測試。
iOSApp
和 AndroidApp
物件不會直接具現化。 而是使用協助程式 ConfigureApp
類別來建立它們。 這個類別是一種產生器,可確保 iOSApp
或 AndroidApp
已正確具現化。
建議您針對每個測試使用新的 IApp
實例。 新的實例可防止狀態從一個測試溢出到另一個測試。 NUnit 測試可以初始化 的 IApp
實例有兩個位置:
SetUp
方法 中,測試裝置通常是相關測試的邏輯群組,每個測試都是彼此獨立執行。 在此案例中SetUp
,IApp
應該在方法中初始化 ,以確保每個測試都有新的 IApp
可用。TestFixtureSetup
在方法 中,在某些情況下,單一測試可能需要自己的測試裝置。 在此情況下,在方法中TestFixtureSetup
初始化IApp
物件一次可能更合理。設定好之後 IApp
,測試可能會開始與所測試的應用程式互動。 若要這樣做,您必須取得螢幕上可見之檢視的參考。 Xamarin.UITest 中的許多方法都會採用 Func<AppQuery, AppQuery>
參數來找出檢視。 例如,下列代碼段示範如何點選按鈕:
app.Tap(c=>c.Button("ValidateButton"));
Xamarin.UITest 架構中有兩個介面實 IApp
作,一個適用於 iOS,另一個用於 Android。
當 Xamarin.UITest 在 iOS 上執行測試時,它會啟動 iOS 模擬器的實例、部署應用程式、啟動它,並開始執行測試。 iOS 應用程式必須已經建置。 Xamarin.UITest 不會編譯應用程式,併為您建立應用程式套件組合。
AppBundle
方法可用來指定可在檔案系統上找到應用程式套件組合的位置。 有兩種方式可以執行這項操作,使用絕對路徑或相對路徑。 這個代碼段顯示使用應用程式套件組合的絕對路徑:
IApp app = ConfigureApp
.iOS
.AppBundle("/path/to/iosapp.app")
.StartApp();
部分路徑必須相對於 Xamarin.UITest 元件。 此代碼段是範例:
IApp app = ConfigureApp
.iOS
.AppBundle("../../../iOSAppProject/bin/iPhoneSimulator/Debug/iosapp.app")
.StartApp();
相對路徑範例會 AppBundle
指示從 Xamarin.UITest 元件向上移至三個目錄,然後流覽 iOS 應用程式專案的專案樹狀結構,以尋找應用程式套件組合。
ConfigureApp
有其他方法來協助設定 IApp
。 如需詳細資訊,請參閱 iOSAppConfigurator 類別。 下表說明一些更有趣的方法:
方法 | Description |
---|---|
AppBundle |
這個方法會指定測試時要使用的應用程式套件組合路徑。 |
Debug |
此方法會在測試執行器中啟用偵錯記錄訊息。 此方法有助於針對在模擬器上執行應用程式的問題進行疑難解答。 |
DeviceIdentifier |
將裝置設定為與裝置標識碼搭配使用。 以下將詳細說明這個方法。 |
EnableLocalScreenshots |
在本機執行測試時啟用螢幕快照。 測試在雲端中執行時,一律會啟用螢幕快照。 |
如需如何在特定 iOS 模擬器上執行 iOS 測試的詳細資訊,請參閱 判斷 iOS 模擬器的裝置標識碼。
Xamarin.UITest 會將現有的 APK 部署到已連結的裝置或已執行的 Android 模擬器實例。 應用程式將會啟動,然後執行測試。 Xamarin.UITest 無法建置 APK,也無法啟動 Android 模擬器的實例。
ApkFile
的 方法是IApp
用來指定可在檔案系統上找到 APK 的位置。 有兩種方式可以執行這項操作,使用絕對路徑或相對路徑。 此代碼段會顯示使用 APK 的絕對路徑:
IApp app = ConfigureApp
.Android
.ApkFile("/path/to/android.apk")
.StartApp();
部分路徑必須相對於 Xamarin.UITest 元件。 此代碼段是範例:
IApp app = ConfigureApp
.Android
.ApkFile("../../../AndroidProject/bin/Debug/android.apk")
.StartApp();
相對路徑範例會 ApkFile
指示從 Xamarin.UITest 元件向上移出三個目錄,然後向覽 Android 應用程式專案的專案樹狀結構,以尋找 apk 檔案。
如果有一個以上的裝置或模擬器連線,Xamarin.UITest 將會停止測試執行,並顯示錯誤訊息,因為無法解決測試的預期目標。 在此情況下,您必須提供裝置或模擬器的 序列標識碼 來執行測試。 例如,請考慮命令的 adb devices
下列輸出,其中列出連結至計算機 (的所有裝置 (或模擬) 器,以及其序列標識元) :
$ adb devices
List of devices attached
192.168.56.101:5555 device
03f80ddae07844d3 device
您可以使用 方法來指定 DeviceSerial
裝置:
IApp app = ConfigureApp.Android.ApkFile("/path/to/android.apk")
.DeviceSerial("03f80ddae07844d3")
.StartApp();
為了與檢視互動,許多 IApp
方法都會採用 Func<AppQuery, AppQuery>
委派來尋找檢視。 此委派會使用 AppQuery
Xamarin.UITest 如何尋找檢視的核心。
AppQuery
是用來建置查詢以尋找檢視的 Fluent 介面 。 在提供的方法 AppQuery
中,方法 Marked
是最簡單且最有彈性的方法之一。 此方法會使用啟發學習法來嘗試尋找檢視,並在下一節中更詳細地討論。 目前,請務必瞭解 IApp
有許多方法可與應用程式互動。 這些方法會使用 Func<AppQuery, AppQuery>
取得要與其互動之檢視的參考。 下面列出一 AppQuery
些更有趣的方法:
方法 | Description |
---|---|
Button |
會在畫面上找到一或多個按鈕。 |
Class |
將會嘗試找出屬於指定類別的檢視。 |
Id |
將會嘗試找出具有指定標識碼的檢視。 |
Index . |
會從相符檢視的集合傳回一個檢視。 通常與其他方法搭配使用。 採用以零起始的索引。 |
Marked |
會根據下面討論的啟發學習法傳回檢視。 |
Text |
將會比對包含所提供文字的檢視。 |
TextField |
將會比對 Android EditText 或 iOS UITextField 。 |
例如,下列方法示範如何模擬名為 「SaveUserdataButton」 的按鈕點選:
app.Tap(c=>c.Marked("SaveUserDataButton"));
因為 AppQuery
是 Fluent 介面,所以可以將多個方法調用鏈結在一起。 請考慮點選檢視的這個更複雜的範例:
app.Tap(c=>c.Marked("Pending")
.Parent()
.Class("AppointmentListCell").Index(0));
在這裡, AppQuery
會先尋找標示 Pending
為 的檢視,然後選取該檢視的第一個 AppointmentListCell
父系,該檢視是類型。
藉由查看行動應用程式,嘗試建立這些查詢可能會很棘手。 Xamarin.UITest 提供 REPL,可用來探索畫面的檢視階層、實驗建立查詢,並使用它們來與應用程式互動。
啟動 REPL 的唯一方法是在現有的測試中叫 IApp.Repl
用 方法。 這需要建立 NUnit TestFixture
,設定 可用於 方法的 Test
實體IApp
。 下列代碼段示範如何執行這項操作的範例:
[TestFixture]
public class ValidateCreditCard
{
IApp app;
[SetUp]
public void Setup()
{
app = ConfigureApp.Android.ApkFile("/path/to/application.apk").StartApp();
}
[Test]
public void CreditCardNumber_TooLong_DisplayErrorMessage()
{
app.Repl();
}
}
若要在 Visual Studio 的裝訂線中按鼠右鍵,然後選取 [ 執行],以執行測試:
測試將會執行,並在叫用 方法時 Repl
,Xamarin.UITest 會在終端機會話中啟動 REPL,如下列螢幕快照所示:
REPL 已初始化名為 的IApp
app
實例,該實例會與應用程式互動。 第一件事之一是探索使用者介面。 REPL 有命令 tree
可執行此動作。 它會列印顯示畫面中的檢視階層。 例如,請考慮應用程式的下列螢幕快照:
我們可以使用 tree
命令來顯示此畫面的下列階層:
App has been initialized to the 'app' variable.
Exit REPL with ctrl-c or see help for more commands.
>>> tree
[UIWindow > UILayoutContainerView]
[UINavigationTransitionView > ... > UIView]
[UITextView] id: "CreditCardTextField"
[_UITextContainerView]
[UIButton] id: "ValidateButton"
[UIButtonLabel] text: "Validate Credit Card"
[UILabel] id: "ErrorrMessagesTestField"
[UINavigationBar] id: "Credit Card Validation"
[_UINavigationBarBackground]
[_UIBackdropView > _UIBackdropEffectView]
[UIImageView]
[UINavigationItemView]
[UILabel] text: "Credit Card Validation"
>>>
我們可以看到 UIButton
此檢視 id
中有 ValidateButton 的 。 我們可以使用 命令所 tree
顯示的信息,協助製作必要的查詢,以找出檢視並與其互動。 例如,下列程式代碼會模擬按鈕上的點選:
app.Tap(c=>c.Marked("ValidateButton"))
當輸入命令時,REPL 會在緩衝區中記住這些命令。 REPL 提供命令 copy
,將這個緩衝區的內容複製到剪貼簿。 這可讓我們建立測試的原型。 我們可以使用 copy
將 REPL 中完成的工作複製到剪貼簿,然後在 中 [Test]
貼上這些命令。
AppQuery.Marked 方法是方便且功能強大的方法來查詢螢幕上的檢視。 其運作方式是檢查畫面上檢視的檢視階層,嘗試比對檢視的屬性與提供的字串。
Marked
會根據操作系統以不同的方式運作。
iOS 檢視會使用下列其中一個屬性來尋找:
AccessibilityIdentifier
的AccessibilityLabel
的例如,請考慮下列 C# 代碼段來建立 UILabel
並設定 AccessibilityLabel
:
UILabel errorMessagesTextField = new UILabel(new RectangleF(10, 210, 300, 40));
errorMessagesTextField.AccessibilityLabel = "ErrorMessagesTextField";
errorMessagesTextField.Text = String.Empty;
此檢視可透過下列查詢找到:
AppResult[] results = app.Marked("ErrorMessagesTextField");
Android 檢視會以下列其中一個屬性為基礎:
Id
的ContentDescription
的Text
檢視的例如,假設Android版面配置已定義下列按鈕:
<Button
android:text="Action 1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/action1_button"
android:layout_weight="1"
android:layout_marginLeft="5dp" />
我們可以看到 android:id
此按鈕的 是action1_button , android:text
而 是 動作 1。 下列兩個查詢中的任一項會在畫面上找到按鈕:
app.Query(c=>c.Marked("action1_button"));
app.Query(c=>c.Marked("Action 1"));
設定並初始化之後 IApp
,測試可能會開始與應用程式互動。 使用 Func<AppQuery, AppQuery>
的方法其中一個範例是 IApp.Query()
方法。 這個方法會執行查詢並傳回結果。 下列代碼段顯示最簡單的範例,其會傳回畫面上可見的所有檢視清單:
AppResult[] results = app.Query(c=>c.All())
下表示範使用 AppQuery
來尋找螢幕上檢視的一些其他範例:
Syntax | 結果 |
---|---|
app.Query(c=>c.Class("UILabel")) |
方法 .Class() 會查詢屬於 iOS UILabel 子類別的檢視。 |
app.Query(c=>c.Id("txtUserName")) |
方法 .Id() 會查詢具有 Id txtUserName 的檢視。 |
app.Query(c=>c.Class("UILabel").Text("Hello, World")) |
UILabel 找出所有具有文字 「Hello, World」 的類別。 |
results = app.Query(c=>c.Marked("ValidateButton")) |
傳回以指定文字 標示 的所有檢視。 方法 Marked 是可簡化查詢的實用方法。 下一節將說明。 |
下表列出一些 (,但並非所有方法) , IApp
這些方法可用來與畫面上的檢視互動或操作:
範例 | 描述 |
---|---|
PressEnter |
在應用程式中按 Enter 鍵。 |
Tap |
仿真相符項目的點選/觸控手勢。 |
EnterText |
在檢視中輸入文字。 在 iOS 應用程式中,Xamarin.UITest 會使用軟式鍵盤輸入文字。 相反地,Xamarin.UITest 不會使用 Android 鍵盤,它會直接在檢視中輸入文字。 |
WaitForElement |
暫停測試的執行,直到檢視出現在畫面上為止。 |
Screenshot(String) |
取得目前狀態的應用程式螢幕快照,並將它儲存至磁碟。 它會傳 FileInfo 回物件,其中包含所擷取螢幕快照的相關信息。 |
Flash |
此方法會導致選取的檢視在螢幕上「閃爍」或「閃爍」。 |
如需 介面的詳細資訊IApp
,請參閱 、 AndroidApp
和 iOSApp
的 IApp
API 檔。
作為如何使用這些方法的範例,請考慮下列測試上方顯示的螢幕快照。 此測試會在文字欄位中輸入信用卡的 17 位數號碼,然後點選畫面上的按鈕。 然後,它會檢查畫面中是否有錯誤訊息,告知用戶號碼太長而無法成為有效的信用卡號碼:
[Test]
public void CreditCardNumber_TooLong_DisplayErrorMessage()
{
/* Arrange - set up our queries for the views */
// Nothing to do here, app has been instantiated in the [SetUp] method.
/* Act */
app.EnterText(c => c.Marked("CreditCardTextField"), new string('9', 17));
// Screenshot can be used to break this test up into "steps".
// The screenshot can be inspected after the test run to verify
// the visual correctness of the screen.
app.Screenshot("Entering a 17 digit credit card number.");
app.Tap(c => c.Marked("ValidateButton"));
app.Screenshot("The validation results.");
/* Assert */
AppResult[] result = app.Query(c => c.Class("UILabel").Text("Credit card number is too long."));
Assert.IsTrue(result.Any(), "The error message isn't being displayed.");
}
此測試也會使用 Screenshot
方法,在測試執行期間於關鍵點拍攝相片。 執行此測試時,App Center 會擷取螢幕快照,並在測試結果中顯示它們。 方法允許將測試分成步驟,並提供螢幕快照的描述。
訓練
模組
Visual Studio 中的 C# 測試 - Training
使用 Visual Studio 中的測試工具來開始測試 C# 應用程式。 了解如何撰寫測試、使用測試總管、建立測試套件,以及套用紅色、綠色、重構模式來撰寫程式碼。