移動應用程式具有獨特的問題,桌面和基于Web的應用程式不必擔心。移動使用者将因其使用的裝置,網絡連接配接,服務可用性以及一系列其他因素而有所不同。是以,應該測試移動應用程式,因為它們将被用于現實世界,以提高其品質,可靠性和性能。應用程式應該執行許多類型的測試,包括單元測試,內建測試和使用者界面測試,單元測試是最常見的測試形式。
單元測試需要應用程式的一小部分,通常是一種方法,将其與代碼的其餘部分隔離,并驗證其是否符合預期。其目标是檢查每個功能單元是否按預期執行,以使整個應用程式不會傳播錯誤。檢測出錯的地方更有效地在二級故障點間接觀察到錯誤的影響。
當它是軟體開發工作流程的組成部分時,單元測試對代碼品質的影響最大。一旦編寫了一個方法,單元測試應該被寫入,以響應标準,邊界和不正确的輸入資料情況來驗證方法的行為,并且檢查代碼所做的任何顯式或隐含的假設。或者,使用測試驅動開發,單元測試是在代碼之前編寫的。在這種情況下,單元測試既可以作為設計文檔和功能規範。
注意:單元測試對于回歸是非常有效的 - 也就是說,以前工作但已被錯誤更新打擾的功能。
單元測試通常使用排列動作斷言模式:
· 單元測試方法的排列部分初始化對象并設定傳遞給被測方法的資料的值。
· act部分使用所需的參數調用被測方法。
· 斷言部分驗證被測方法的動作是否符合預期。
遵循此模式可確定單元測試可讀和一緻。
采用松散耦合架構的動機之一是它有助于單元測試。 Autofac注冊的類型之一是OrderService類。 以下代碼示例顯示了此類的大綱:
點選(此處)折疊或打開
public class OrderDetailViewModel : ViewModelBase
{
private IOrderService _ordersService;
public OrderDetailViewModel(IOrderService ordersService)
{
_ordersService = ordersService;
}
...
}
OrderDetailViewModel類具有對IOrderService類型的依賴關系,當容器執行個體化一個OrderDetailViewModel對象時,該容器将被解析。 但是,而不是建立一個OrderService對象來單元測試OrderDetailViewModel類,而不是為了測試而将OrderService對象替換為模拟。 圖10-1說明了這種關系。

圖10-1:實作IOrderService接口的類
此方法允許在運作時将OrderService對象傳遞到OrderDetailViewModel類中,為了可測試性,它允許在測試時将OrderMockService類傳遞到OrderDetailViewModel類中。 這種方法的主要優點是它可以執行單元測試,而不需要諸如Web服務或資料庫之類的笨重資源。
從MVVM應用程式中測試模型和檢視模型與測試任何其他類相同,可以使用相同的工具和技術(如單元測試和模拟)。然而,有一些典型的模型和模型類的模式,可以從特定的單元測試技術中受益。
? 提示:每個單元測試測試一件事。不要試圖對機關的行為進行單元測試。這樣做會導緻難以閱讀和更新的測試。解釋失敗時也可能導緻混亂。
· 事實是總是真實的測試,它測試不變的條件。
· 理論是僅針對特定資料集的測試。
eShopOnContainers手機應用程式附帶的單元測試是事實測試,是以每個單元測試方法都使用[Fact]屬性進行裝飾。
注意:xUnit測試由測試運作器執行。要執行測試運作器,請為所需的平台運作eShopOnContainers.TestRunner項目。
在實作MVVM模式時,視圖模型通常會以異步方式調用服務操作。 調用這些操作的代碼的測試通常使用mock作為實際服務的替換。 以下代碼示例示範了通過将模拟服務傳遞到視圖模型中來測試異步功能:
[Fact]
public async Task OrderPropertyIsNotNullAfterViewModelInitializationTest()
var orderService = new OrderMockService();
var orderViewModel = new OrderDetailViewModel(orderService);
var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
await orderViewModel.InitializeAsync(order);
Assert.NotNull(orderViewModel.Order);
當OrderDetailViewModel執行個體被建立時,它期望一個OrderService執行個體被指定為一個參數。 但是,OrderService從Web服務檢索資料。 是以,OrderMockService執行個體(它是OrderService類的模拟版本)被指定為OrderDetailViewModel構造函數的參數。 然後,當調用視圖模型的InitializeAsync方法(調用IOrderService操作)時,将檢索模拟資料,而不是與Web服務通信。
實作INotifyPropertyChanged接口允許視圖對來自視圖模型和模型的更改做出反應。 這些更改不限于控件中顯示的資料 - 它們也用于控制視圖,例如檢視模型狀态,導緻動畫啟動或禁用控件。
可以通過單元測試直接更新的屬性可以通過将事件處理程式附加到PropertyChanged事件并在為屬性設定新值後檢查事件是否引發來測試。 以下代碼示例顯示了這樣一個測試:
public async Task SettingOrderPropertyShouldRaisePropertyChanged()
bool invoked = false;
orderViewModel.PropertyChanged += (sender, e) =>
if (e.PropertyName.Equals("Order"))
invoked = true;
};
Assert.True(invoked);
該單元測試調用OrderViewModel類的InitializeAsync方法,這會導緻其Order屬性被更新。 單元測試将通過,前提是PropertyChanged事件為Order屬性生成。
使用MessagingCenter類在松散耦合類之間通信的檢視模型可以通過訂閱被測試代碼發送的消息進行單元測試,如以下代碼示例所示:
public void AddCatalogItemCommandSendsAddProductMessageTest()
bool messageReceived = false;
var catalogService = new CatalogMockService();
var catalogViewModel = new CatalogViewModel(catalogService);
Xamarin.Forms.MessagingCenter.SubscribeCatalogViewModel, CatalogItem>(
this, MessageKeys.AddProduct, (sender, arg) =>
messageReceived = true;
});
catalogViewModel.AddCatalogItemCommand.Execute(null);
Assert.True(messageReceived);
此單元測試檢查CatalogViewModel是否釋出AddProduct消息以響應其AddCatalogItemCommand被執行。 因為MessagingCenter類支援多點傳播消息訂閱,是以單元測試可以訂閱AddProduct消息并執行回調委托以響應接收它。 此回調委托,指定為lambda表達式,設定Assert語句使用的布爾字段,以驗證測試的行為。
也可以寫出單元測試,檢查是否針對無效操作或輸入引發特定異常,如以下代碼示例所示:
public void InvalidEventNameShouldThrowArgumentExceptionText()
var behavior = new MockEventToCommandBehavior
EventName = "OnItemTapped"
var listView = new ListView();
Assert.ThrowsArgumentException>(() => listView.Behaviors.Add(behavior));
此單元測試将抛出異常,因為ListView控件沒有名為OnItemTapped的事件。 Assert.Throws 方法是一種通用方法,其中T是預期異常的類型。 傳遞給Assert.Throws 方法的參數是一個将表示異常的lambda表達式。 是以,單元測試将通過,隻要lambda表達式抛出一個ArgumentException。
? 提示:避免編寫檢查異常消息字元串的單元測試。 異常消息字元串可能随時間而變化,是以依賴于它們的存在的單元測試被認為是脆弱的。
測試驗證實作有兩個方面:測試任何驗證規則是否正确實作,并測試ValidatableObject 類按預期執行。
驗證邏輯通常很容易測試,因為它通常是一個獨立的過程,其中輸出取決于輸入。 對于具有至少一個關聯驗證規則的每個屬性,調用Validate方法的結果應該是測試的,如下面的代碼示例所示:
public void CheckValidationPassesWhenBothPropertiesHaveDataTest()
var mockViewModel = new MockViewModel();
mockViewModel.Forename.Value = "John";
mockViewModel.Surname.Value = "Smith";
bool isValid = mockViewModel.Validate();
Assert.True(isValid);
當MockViewModel執行個體中的兩個ValidatableObject 屬性都具有資料時,此單元測試會檢查驗證是否成功。
除了檢查驗證成功之外,驗證單元測試還應檢查每個ValidatableObject 執行個體的Value,IsValid和Errors屬性的值,以驗證該類是否按預期執行。 以下代碼示例示範了執行此操作的單元測試:
public void CheckValidationFailsWhenOnlyForenameHasDataTest()
Assert.False(isValid);
Assert.NotNull(mockViewModel.Forename.Value);
Assert.Null(mockViewModel.Surname.Value);
Assert.True(mockViewModel.Forename.IsValid);
Assert.False(mockViewModel.Surname.IsValid);
Assert.Empty(mockViewModel.Forename.Errors);
Assert.NotEmpty(mockViewModel.Surname.Errors);
當MockViewModel的Surname屬性沒有任何資料,并且正确設定每個ValidatableObject 執行個體的Value,IsValid和Errors屬性時,此單元測試将檢查驗證失敗。
單元測試需要應用程式的一小部分,通常是一種方法,将其與代碼的其餘部分隔離,并驗證其是否符合預期。 其目标是檢查每個功能單元是否按預期執行,以使整個應用程式不會傳播錯誤。
可以通過用模拟依賴對象行為的模拟對象替換依賴對象來隔離被測對象的行為。 這樣可以在不需要諸如Web服務或資料庫等笨重資源的情況下執行單元測試。
從MVVM應用程式測試模型和檢視模型與測試任何其他類相同,可以使用相同的工具和技術。