UITesting 界面测试

1. 创建界面测试视图 UITestingBootcampView.swift

import SwiftUI/// 界面测试 ViewModel
class UITestingBootcampViewModel: ObservableObject{let placeholderText: String = "Add name here..."@Published var textFiledText: String = ""@Published var currentUserIsSignedIn: Boolinit(currentUserIsSignedIn: Bool) {self.currentUserIsSignedIn = currentUserIsSignedIn}/// 登录按钮处理,模拟测试func signUpButtonPressed() {guard !textFiledText.isEmpty else { return }currentUserIsSignedIn = true}
}/// 界面测试
struct UITestingBootcampView: View {@StateObject private var viewModel: UITestingBootcampViewModelinit(currentUserIsSignedIn: Bool) {//"_" 下划线表示: 正在引用状态对象  wrappedValue: 表示包装值_viewModel = StateObject(wrappedValue: UITestingBootcampViewModel(currentUserIsSignedIn: currentUserIsSignedIn))print("description: " + currentUserIsSignedIn.description)}var body: some View {ZStack {LinearGradient(gradient: Gradient(colors: [Color.blue, Color.black]),startPoint: .topLeading,endPoint: .bottomTrailing).ignoresSafeArea()ZStack {if viewModel.currentUserIsSignedIn {SignedInHomeView().frame(maxWidth:.infinity, maxHeight: .infinity).transition(.move(edge: .trailing))}if !viewModel.currentUserIsSignedIn{signUpLayer.frame(maxWidth:.infinity, maxHeight: .infinity).transition(.move(edge: .leading))}}}}
}/// 扩展 View
extension UITestingBootcampView{// 登录布局private var signUpLayer: some View{VStack {TextField(viewModel.placeholderText, text: $viewModel.textFiledText).font(.headline).padding().frame(height: 55).background(Color.white).cornerRadius(10).accessibilityIdentifier("SignUpTextField")Button {withAnimation(.spring()) {viewModel.signUpButtonPressed()}} label: {Text("Sign Up").font(.headline).padding().frame(maxWidth: .infinity).foregroundColor(.white).background(Color.accentColor).cornerRadius(10)}.accessibilityIdentifier("SignUpButton")}.padding()}
}/// 登录入主页
struct SignedInHomeView: View{@State private var showAlert: Bool = falsevar body: some View{NavigationView {VStack(spacing: 20) {Button {showAlert.toggle()} label: {Text("Show welcome alert!").font(.headline).padding().frame(maxWidth: .infinity).foregroundColor(.white).background(Color.red).cornerRadius(10)}.accessibilityIdentifier("ShowAlertButton").alert(isPresented: $showAlert) {return Alert(title: Text("Welcome to the app!"))}NavigationLink(destination: Text("Destination")) {Text("Navigate").font(.headline).padding().frame(maxWidth: .infinity).foregroundColor(.white).background(Color.blue).cornerRadius(10)}.accessibilityIdentifier("NavigationLinkToDestination")}.padding().navigationTitle("Welcome")}}
}struct UITestingBootcampView_Previews: PreviewProvider {static var previews: some View {UITestingBootcampView(currentUserIsSignedIn: true)}
}

2. 测试类及自动操作效果图

  2.1 添加界面测试类

      添加方法与单元测试类添加方法一样,注意的是 Test 栏下 选择 UI Testing Bundle。

      创建界面测试文件 UITestingBootcampView_UITests.swift

import XCTest// 《Testing Swift》 测试书籍
// 书籍网址: https://www.hackingwithswift.com/store/testing-swift
// Naming Structure: test_UnitOfWork_StateUnderTest_ExpectedBehavior -  结构体命名: 测试_工作单元_测试状态_预期的行为
// Naming Structure: test_[struct]_[ui component]_[expected result] - 测试_[结构体]_[界面 组件]_[预期结果 预期值]
// Testing Structure: Given, When, Then - 测试结构: 给定,什么时候,然后final class UITestingBootcampView_UITests: XCTestCase {let app = XCUIApplication()override func setUpWithError() throws {continueAfterFailure = false//app.launchArguments = ["-UITest_startSignedIn"]//app.launchEnvironment = ["-UITest_startSignedIn2" : "true"]app.launch()}override func tearDownWithError() throws {}/// 测试_界面测试视图_注册按钮_不能登录func test_UITestingBootcampView_signUpButton_shouldNotSignIn(){// GivensignUpAndSignIn(shouldTypeOnKeyboard: false)// Whenlet navBar = app.navigationBars["Welcome"]// Then 断言导航栏不存在XCTAssertFalse(navBar.exists)}/// 测试_界面测试视图_注册按钮_能登录func test_UITestingBootcampView_signUpButton_shouldSignIn(){// GivensignUpAndSignIn(shouldTypeOnKeyboard: true)// Whenlet navBar = app.navigationBars["Welcome"]// Then 断言导航栏存在XCTAssertTrue(navBar.exists)}/// 测试_登录到主页_显示警告按钮_能显示警告弹框func test_SignedInHomeView_showAlertButton_shouldDisplayAlert(){// GivensignUpAndSignIn(shouldTypeOnKeyboard: true)// WhentapAlertButton(shouldDismissAlert: false)// Then// 查找第一个警告框let alert = app.alerts.firstMatch// 警告框是否存在XCTAssertTrue(alert.exists)}/// 测试_登录到主页_显示警告按钮_能显示并关闭警告弹框func test_SignedInHomeView_showAlertButton_shouldDisplayAndDismissAlert(){// GivensignUpAndSignIn(shouldTypeOnKeyboard: true)// WhentapAlertButton(shouldDismissAlert: true)// Then 断言// sleep(1)// 查找第一个警告框,存不存在let alertExists = app.alerts.firstMatch.waitForExistence(timeout: 5)XCTAssertFalse(alertExists)}/// 测试_登录到主页_导航连接器_能够跳转到func test_SignedInHomeView_navigationLinkToDestination_shouldNavigateToDestination(){// GivensignUpAndSignIn(shouldTypeOnKeyboard: true)// WhentapNavigationLink(shouldDismissDestination: false)//then 断言文本是否存在let destinationText = app.staticTexts["Destination"]XCTAssertTrue(destinationText.exists)}/// 测试_登录到主页_导航连接到目标视图_能显示并关闭警告弹框func test_SignedInHomeView_navigationLinkToDestination_shouldNavigateToDestinationAndGoBack(){// GivensignUpAndSignIn(shouldTypeOnKeyboard: true)// WhentapNavigationLink(shouldDismissDestination: true)//then 断言 Home View 导航栏是否存在let navBar = app.navigationBars["Welcome"]// 导航栏是否存在XCTAssertTrue(navBar.exists)}/// 测试_登录到主页_导航连接到目标视图_能显示并关闭警告弹框
//    func test_SignedInHomeView_navigationLinkToDestination_shouldNavigateToDestinationAndGoBack2(){
//        // Given
//
//        // When
//        tapNavigationLink(shouldDismissDestination: true)
//
//        //then 断言 Home View 导航栏是否存在
//        let navBar = app.navigationBars["Welcome"]
//        // 导航栏是否存在
//        XCTAssertTrue(navBar.exists)
//    }
}// MARK: 也许可能函数
extension UITestingBootcampView_UITests{/// 提取公共部分代码 注册并登录,键盘输入: trur falsefunc signUpAndSignIn(shouldTypeOnKeyboard: Bool){let textfield = app.textFields["SignUpTextField"]textfield.tap()if shouldTypeOnKeyboard {let keyA = app.keys["A"]keyA.tap()let keyA1 = app.keys["a"]keyA1.tap()keyA1.tap()let returnButton = app.buttons["Return"]returnButton.tap()}let signUpButton = app.buttons["SignUpButton"]signUpButton.tap()}/// 提取提示框按钮,是否关闭提示框func tapAlertButton(shouldDismissAlert: Bool){let showAlertButton = app.buttons["ShowAlertButton"]showAlertButton.tap()if shouldDismissAlert{// 查找第一个警告框 中的 OK 按钮let alertOKButton = app.alerts.firstMatch.buttons["OK"]// sleep(1)// 等待至少 5 秒,让 alertOKButton 存在let alertPKButtonExists =  alertOKButton.waitForExistence(timeout: 5)// 断言按钮是否存在XCTAssertTrue(alertPKButtonExists)alertOKButton.tap()}}/// 提取导航连接器 ,是否关闭目标视图func tapNavigationLink(shouldDismissDestination: Bool){// 导航器按钮let navLinkButton = app.buttons["NavigationLinkToDestination"]navLinkButton.tap()if shouldDismissDestination{// 返回按钮let backButton = app.navigationBars.buttons["Welcome"]backButton.tap()}}
}

  2.2 点击 test_UITestingBootcampView_signUpButton_shouldNotSignIn 测试方法前 方形运行按钮,得到测试效果,如图:

  2.3 如上测试方法 test_SignedInHomeView_showAlertButton_shouldDisplayAlert 效果图:

  2.4 其他测试方法操作,如上一致。

3. 从 App 启动类中加载界面测试 View,界面测试时,App 启动类中也需要添加界面测试 View

  3.1 可配启动参数,菜单栏点击 Product -> Scheme -> Edit Scheme... -> Run 选项卡页添加参数,如图:

  3.2 获取配置参数,加载测试界面视图 SwiftfulThinkingAdvancedLearningApp.swift

import SwiftUI@main
struct SwiftfulThinkingAdvancedLearningApp: App {let currentUserIsSignedIn: Boolinit() {// 获取启动参数,判断是否有此字符串: UITestingBootcampView// let userIsSignedIn:Bool = CommandLine.arguments.contains("-UITest_startSignedIn") ? true : falselet userIsSignedIn:Bool = ProcessInfo.processInfo.arguments.contains("-UITest_startSignedIn") ? true : false// 获取环境变量配置值// let value = ProcessInfo.processInfo.environment["-UITest_startSignedIn2"]// let userIsSignedIn:Bool =  value == "true" ? true : falseself.currentUserIsSignedIn = userIsSignedIn//print("USER IS SIGNED IN: \(userIsSignedIn)")//print("USER IS SIGNED IN2: \(value ?? "")")}var body: some Scene {WindowGroup {UITestingBootcampView(currentUserIsSignedIn: self.currentUserIsSignedIn)}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/112996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023年中国一次性医用内窥镜市场发展现状分析:相关产品进入上市高峰期[图]

基于对减少交叉感染风险和维护成本的需求等因素,一种新兴的、耗材化的一次性内窥镜可以避免因重复使用产品而导致的感染问题和高额的清洗消毒费用,从而提高患者的安全性并帮助医疗机构节省运营成本。 一次性和可重复使用医用内窥镜特点对比 资料来源&am…

Android 指定有线网或Wifi进行网络请求

Android 指定有线网或Wifi进行网络请求 文章目录 Android 指定有线网或Wifi进行网络请求一、前言:二、指定网络通讯测试1、 窗口命令 ping -I 网络节点 IP2、Java 代码指定特定网络通讯 三、指定特定网络的demo app 开发1、效果图:2、实际测试结果说明&a…

Nginx负载均衡反向代理动静分离

文章目录 nginx负载均衡&反向代理&动静分离环境说明部署动静分离1.主机lnmp部署一个动态页面,在此以discuz论坛系统为例2.主机n1部署两个静态页面访问动、静态页面 配置负载均衡配置反向代理访问测试 nginx负载均衡&反向代理&动静分离 环境 主机名…

【LINUX】1-移植NXP提供的源码

一、在Linux中添加自己的开发板 defconfig配置文件:一个就是imx6ull_alientek_emmc_defconfig默认配置文件 # 复制一份NXP 官方的SDK cd arch/arm/configs cp imx_v7_mfg_defconfig imx_alientek_emmc_defconfig 设备树:imx6ull-alientek-emmc.d…

【Arduino32】PWM控制直流电机速度

硬件准备 震动传感器:1个 红黄绿LED灯:各一个 旋钮电位器:1个 直流电机:1个 1K电阻:1个 220欧电阻:3个 杜邦线:若干 硬件连线 软件程序 const int analogInPin A0;//PWM输入引脚 const…

SpringCloud链路追踪——Spring Cloud Sleuth 和 Zipkin 介绍 Windows 下使用初步

前言 在微服务中,随着服务越来越多,对调用链的分析越来越复杂。如何能够分析调用链,定位微服务中的调用瓶颈,并对其进行解决。 本篇博客介绍springCloud中用到的链路追踪的组件,Spring Cloud Sleuth和Zipkin&#xf…

使用 PyAudio、语音识别、pyttsx3 和 SerpApi 构建简单的基于 CLI 的语音助手

德米特里祖布☀️ 一、介绍 正如您从标题中看到的,这是一个演示项目,显示了一个非常基本的语音助手脚本,可以根据 Google 搜索结果在终端中回答您的问题。 您可以在 GitHub 存储库中找到完整代码:dimitryzub/serpapi-demo-project…

Git的安装

前置 知道自己电脑上跑的是什么系统 查看电脑位数 省事的一种办法 Windows 在cmd中输入如下命令 wmic os get osarchitecture看命令结果即可 省事的一种办法 Linux 直接在终端中输入如下命令 uname -m若结果是x86_64就是64位的,反之32位 图形化的办法 Wind…

开箱即用的Appimage是什么以及如何建立快捷方式

1 引言 在使用Linux系统过程中,初学者会遇到无穷多的问题,包括软件的安装问题。 ubuntu的deb,centos的rpm, 当然以及需要解压的tar.gz等等。有一种开箱即用的软件安装类型,格式为Appimage。 AppImage 的官方网站是 AppImage | Linux apps tha…

文件打包下载excel导出和word导出

0.文件下载接口 请求 GET /pm/prj/menu/whsj/download/{affixId} 文件affixId多个id以逗号隔开。多个文件会以打包得形式。 1.Excel导出 1.0接口 POST 127.0.0.1:8400/pm/io/exportExcel/year-plan-table-workflow/report 参数 [{"org":"011","re…

java8 Optional理解及示例

大量判空的代码 实际中,对象不判空会导致空指针异常。 为了规避为指针,不得不写出这种非常冗长又丑陋的空指针判断。 public void tooMuchNull(Worker worker) {if (worker ! null) {Address addressworker.getAddress();if (address ! null) {String…

react-router-dom v6版本实现Tabs路由缓存切换

目录 文章目录 概要 效果 完整代码 概要 摆了半年摊,好久没写代码了,今天有人问我怎么实现React-Router-dom类似标签页缓存。后面看了一下router的官网。很久以前用的是react-router v5那个比较容易实现。v6变化挺大,但了解react的机制和rea…

Android一些新的技术栈,你都会哪些?

Jetpack Compose: Jetpack Compose是一种全新的声明式UI框架,用于构建Android应用的用户界面。它使UI开发更加简单和直观,通过使用Kotlin语言来创建交互式和动态的UI组件。 Kotlin Multiplatform: Kotlin Multiplatform允许开发者…

2023年【北京市安全员-A证】考试报名及北京市安全员-A证考试资料

题库来源:安全生产模拟考试一点通公众号小程序 北京市安全员-A证考试报名根据新北京市安全员-A证考试大纲要求,安全生产模拟考试一点通将北京市安全员-A证模拟考试试题进行汇编,组成一套北京市安全员-A证全真模拟考试试题,学员可…

【LeetCode】59. 螺旋矩阵 II

1 问题 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1: 输入:n 3 输出:[[1,2,3],[8,9,4],[7,6,5]] 示例 2: 输入:n…

windows 11 安装PHP8.2

环境说明 windows:windows 11 x64apache: Apache/2.4.43php :php-8.2.11 一.php 1、PHP下载 PHP For Windows: Binaries and sources Releases 注意: 1.要下载Thread Safe,否则没有php8apache2_4.dll这个文件;如果使用Apache作为服务器…

SpringSecurity+ Oauth2.0+JWT 0-1

这里写目录标题 准备工作准备SQL添加用户添加依赖准备UserInfoUserMapperUserServiceUserServiceImpl配置SpringDataUserDetailsService 授权服务器:AuthorizationServer配置客户端详细信息管理令牌定义TokenConfig定义AuthorizationServerTokenServices 令牌访问端…

Python爬虫基础之Selenium详解

目录 1. Selenium简介2. 为什么使用Selenium?3. Selenium的安装4. Selenium的使用5. Selenium的元素定位6. Selenium的交互7. Chrome handless参考文献 原文地址:https://program-park.top/2023/10/16/reptile_3/ 本文章中所有内容仅供学习交流使用&…

左连接一对多的情况

左连接一对多时候,应该以主表唯一数据为左表 GROUP_CONCAT()

Flutter之Widget生命周期

目录 初始化构造函数initStatedidChangeDependencies 运行时builddidUpdateWidget 组件移除deactivatedisposereassemble 函数生命周期说明:实际场景App生命周期 前言:生命周期是一个组件加载到卸载的整个周期,熟悉生命周期可以让我们在合适的…