使用Xamarin.Forms的企业应用程序模式(电子书)--单元测试

简介: 移动应用程序具有独特的问题,桌面和基于Web的应用程序不必担心。移动用户将因其使用的设备,网络连接,服务可用性以及一系列其他因素而有所不同。因此,应该测试移动应用程序,因为它们将被用于现实世界,以提高其质量,可靠性和性能。

移动应用程序具有独特的问题,桌面和基于Web的应用程序不必担心。移动用户将因其使用的设备,网络连接,服务可用性以及一系列其他因素而有所不同。因此,应该测试移动应用程序,因为它们将被用于现实世界,以提高其质量,可靠性和性能。应用程序应该执行许多类型的测试,包括单元测试,集成测试和用户界面测试,单元测试是最常见的测试形式。

单元测试需要应用程序的一小部分,通常是一种方法,将其与代码的其余部分隔离,并验证其是否符合预期。其目标是检查每个功能单元是否按预期执行,以使整个应用程序不会传播错误。检测出错的地方更有效地在二级故障点间接观察到错误的影响。

当它是软件开发工作流程的组成部分时,单元测试对代码质量的影响最大。一旦编写了一个方法,单元测试应该被写入,以响应标准,边界和不正确的输入数据情况来验证方法的行为,并且检查代码所做的任何显式或隐含的假设。或者,使用测试驱动开发,单元测试是在代码之前编写的。在这种情况下,单元测试既可以作为设计文档和功能规范。

注意:单元测试对于回归是非常有效的 - 也就是说,以前工作但已被错误更新打扰的功能。

单元测试通常使用排列动作断言模式:

· 单元测试方法的排列部分初始化对象并设置传递给被测方法的数据的值。

· act部分使用所需的参数调用被测方法。

· 断言部分验证被测方法的动作是否符合预期。

遵循此模式可确保单元测试可读和一致。

依赖注入和单元测试

采用松散耦合架构的动机之一是它有助于单元测试。 Autofac注册的类型之一是OrderService类。 以下代码示例显示了此类的大纲:


点击(此处)折叠或打开

  1. public class OrderDetailViewModel : ViewModelBase
  2. {
  3.     private IOrderService _ordersService;

  4.     public OrderDetailViewModel(IOrderService ordersService)
  5.     {
  6.         _ordersService = ordersService;
  7.     }
  8.     ...
  9. }


OrderDetailViewModel类具有对IOrderService类型的依赖关系,当容器实例化一个OrderDetailViewModel对象时,该容器将被解析。 但是,而不是创建一个OrderService对象来单元测试OrderDetailViewModel类,而不是为了测试而将OrderService对象替换为模拟。 图10-1说明了这种关系。

 

10-1:实现IOrderService接口的类

此方法允许在运行时将OrderService对象传递到OrderDetailViewModel类中,为了可测试性,它允许在测试时将OrderMockService类传递到OrderDetailViewModel类中。 这种方法的主要优点是它可以执行单元测试,而不需要诸如Web服务或数据库之类的笨重资源。

测试MVVM应用程序

MVVM应用程序中测试模型和查看模型与测试任何其他类相同,可以使用相同的工具和技术(如单元测试和模拟)。然而,有一些典型的模型和模型类的模式,可以从特定的单元测试技术中受益。

? 提示:每个单元测试测试一件事。不要试图对单位的行为进行单元测试。这样做会导致难以阅读和更新的测试。解释失败时也可能导致混乱。

eShopOnContainers手机应用程序使用xUnit执行单元测试,它支持两种不同类型的单元测试:

· 事实是总是真实的测试,它测试不变的条件。

· 理论是仅针对特定数据集的测试。

eShopOnContainers手机应用程序附带的单元测试是事实测试,因此每个单元测试方法都使用[Fact]属性进行装饰。

注意:xUnit测试由测试运行器执行。要执行测试运行器,请为所需的平台运行eShopOnContainers.TestRunner项目。

测试异步功能

在实现MVVM模式时,视图模型通常会以异步方式调用服务操作。 调用这些操作的代码的测试通常使用mock作为实际服务的替换。 以下代码示例演示了通过将模拟服务传递到视图模型中来测试异步功能:


点击(此处)折叠或打开

  1. [Fact]
  2. public async Task OrderPropertyIsNotNullAfterViewModelInitializationTest()
  3. {
  4.     var orderService = new OrderMockService();
  5.     var orderViewModel = new OrderDetailViewModel(orderService);

  6.     var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
  7.     await orderViewModel.InitializeAsync(order);

  8.     Assert.NotNull(orderViewModel.Order);
  9. }


此单元测试检查OrderDetailViewModel实例的Order属性在InitializeAsync方法被调用后将具有一个值。 当视图模型的对应视图导航到时,将调用InitializeAsync方法。 有关导航的更多信息,请参阅导航

OrderDetailViewModel实例被创建时,它期望一个OrderService实例被指定为一个参数。 但是,OrderService从Web服务检索数据。 因此,OrderMockService实例(它是OrderService类的模拟版本)被指定为OrderDetailViewModel构造函数的参数。 然后,当调用视图模型的InitializeAsync方法(调用IOrderService操作)时,将检索模拟数据,而不是与Web服务通信。

测试INotifyPropertyChanged实现

实现INotifyPropertyChanged接口允许视图对来自视图模型和模型的更改做出反应。 这些更改不限于控件中显示的数据 - 它们也用于控制视图,例如查看模型状态,导致动画启动或禁用控件。

可以通过单元测试直接更新的属性可以通过将事件处理程序附加到PropertyChanged事件并在为属性设置新值后检查事件是否引发来测试。 以下代码示例显示了这样一个测试:


点击(此处)折叠或打开

  1. [Fact]
  2. public async Task SettingOrderPropertyShouldRaisePropertyChanged()
  3. {
  4.     bool invoked = false;
  5.     var orderService = new OrderMockService();
  6.     var orderViewModel = new OrderDetailViewModel(orderService);

  7.     orderViewModel.PropertyChanged += (sender, e) =>
  8.     {
  9.         if (e.PropertyName.Equals("Order"))
  10.             invoked = true;
  11.     };
  12.     var order = await orderService.GetOrderAsync(1, GlobalSetting.Instance.AuthToken);
  13.     await orderViewModel.InitializeAsync(order);

  14.     Assert.True(invoked);
  15. }


该单元测试调用OrderViewModel类的InitializeAsync方法,这会导致其Order属性被更新。 单元测试将通过,前提是PropertyChanged事件为Order属性生成。

测试基于消息的通信

使用MessagingCenter类在松散耦合类之间通信的查看模型可以通过订阅被测试代码发送的消息进行单元测试,如以下代码示例所示:


点击(此处)折叠或打开

  1. [Fact]
  2. public void AddCatalogItemCommandSendsAddProductMessageTest()
  3. {
  4.     bool messageReceived = false;
  5.     var catalogService = new CatalogMockService();
  6.     var catalogViewModel = new CatalogViewModel(catalogService);

  7.     Xamarin.Forms.MessagingCenter.SubscribeCatalogViewModel, CatalogItem>(
  8.         this, MessageKeys.AddProduct, (sender, arg) =>
  9.     {
  10.         messageReceived = true;
  11.     });
  12.     catalogViewModel.AddCatalogItemCommand.Execute(null);

  13.     Assert.True(messageReceived);
  14. }


此单元测试检查CatalogViewModel是否发布AddProduct消息以响应其AddCatalogItemCommand被执行。 因为MessagingCenter类支持多播消息订阅,所以单元测试可以订阅AddProduct消息并执行回调委托以响应接收它。 此回调委托,指定为lambda表达式,设置Assert语句使用的布尔字段,以验证测试的行为。

测试异常处理

也可以写出单元测试,检查是否针对无效操作或输入引发特定异常,如以下代码示例所示:


点击(此处)折叠或打开

  1. [Fact]
  2. public void InvalidEventNameShouldThrowArgumentExceptionText()
  3. {
  4.     var behavior = new MockEventToCommandBehavior
  5.     {
  6.         EventName = "OnItemTapped"
  7.     };
  8.     var listView = new ListView();

  9.     Assert.ThrowsArgumentException>(() => listView.Behaviors.Add(behavior));
  10. }


此单元测试将抛出异常,因为ListView控件没有名为OnItemTapped的事件。 Assert.Throws 方法是一种通用方法,其中T是预期异常的类型。 传递给Assert.Throws 方法的参数是一个将表示异常的lambda表达式。 因此,单元测试将通过,只要lambda表达式抛出一个ArgumentException。

 

? 提示:避免编写检查异常消息字符串的单元测试。 异常消息字符串可能随时间而变化,因此依赖于它们的存在的单元测试被认为是脆弱的。

测试验证

测试验证实现有两个方面:测试任何验证规则是否正确实现,并测试ValidatableObject 类按预期执行。

验证逻辑通常很容易测试,因为它通常是一个独立的过程,其中输出取决于输入。 对于具有至少一个关联验证规则的每个属性,调用Validate方法的结果应该是测试的,如下面的代码示例所示:


点击(此处)折叠或打开

  1. [Fact]
  2. public void CheckValidationPassesWhenBothPropertiesHaveDataTest()
  3. {
  4.     var mockViewModel = new MockViewModel();
  5.     mockViewModel.Forename.Value = "John";
  6.     mockViewModel.Surname.Value = "Smith";

  7.     bool isValid = mockViewModel.Validate();

  8.     Assert.True(isValid);
  9. }


MockViewModel实例中的两个ValidatableObject 属性都具有数据时,此单元测试会检查验证是否成功。

除了检查验证成功之外,验证单元测试还应检查每个ValidatableObject 实例的Value,IsValid和Errors属性的值,以验证该类是否按预期执行。 以下代码示例演示了执行此操作的单元测试:


点击(此处)折叠或打开

  1. [Fact]
  2. public void CheckValidationFailsWhenOnlyForenameHasDataTest()
  3. {
  4.     var mockViewModel = new MockViewModel();
  5.     mockViewModel.Forename.Value = "John";

  6.     bool isValid = mockViewModel.Validate();

  7.     Assert.False(isValid);
  8.     Assert.NotNull(mockViewModel.Forename.Value);
  9.     Assert.Null(mockViewModel.Surname.Value);
  10.     Assert.True(mockViewModel.Forename.IsValid);
  11.     Assert.False(mockViewModel.Surname.IsValid);
  12.     Assert.Empty(mockViewModel.Forename.Errors);
  13.     Assert.NotEmpty(mockViewModel.Surname.Errors);
  14. }


MockViewModel的Surname属性没有任何数据,并且正确设置每个ValidatableObject 实例的Value,IsValid和Errors属性时,此单元测试将检查验证失败。

概要

单元测试需要应用程序的一小部分,通常是一种方法,将其与代码的其余部分隔离,并验证其是否符合预期。 其目标是检查每个功能单元是否按预期执行,以使整个应用程序不会传播错误。

可以通过用模拟依赖对象行为的模拟对象替换依赖对象来隔离被测对象的行为。 这样可以在不需要诸如Web服务或数据库等笨重资源的情况下执行单元测试。

MVVM应用程序测试模型和查看模型与测试任何其他类相同,可以使用相同的工具和技术。

目录
相关文章
|
7月前
|
SQL 安全 测试技术
Web应用程序安全测试
Web应用程序安全测试
198 0
|
7月前
|
Linux Android开发
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
131 0
|
11天前
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
56 13
|
17天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
46 1
|
2月前
|
安全 Linux 网络安全
Kali渗透测试:远程控制程序基础
Kali渗透测试:远程控制程序基础
40 0
Kali渗透测试:远程控制程序基础
|
2月前
|
安全 Java Linux
Kali渗透测试:通过Web应用程序实现远程控制
Kali渗透测试:通过Web应用程序实现远程控制
49 0
|
4月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
103 0
|
5月前
|
开发框架 JSON 前端开发
基于ABP框架的SignalR,使用Winform程序进行功能测试
基于ABP框架的SignalR,使用Winform程序进行功能测试
|
6月前
|
运维 DataWorks Oracle
DataWorks产品使用合集之在标准模式下,当同步Oracle的表或视图时,是否需要在源端的测试和生产环境中都存在要同步的表或视图
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
49 3
|
5月前
|
运维 监控 大数据
部署-Linux01,后端开发,运维开发,大数据开发,测试开发,后端软件,大数据系统,运维监控,测试程序,网页服务都要在Linux中进行部署
部署-Linux01,后端开发,运维开发,大数据开发,测试开发,后端软件,大数据系统,运维监控,测试程序,网页服务都要在Linux中进行部署