复习

3 阅读17分钟

Selenium定位元素的方法有哪些?

面试的时候,尽量多,全面的说出自己掌握的Selenium定位元素的方法:

  1. 按ID定位:通过元素的id属性来定位元素,使用find_element_by_id方法。
  2. 按Name定位:通过元素的name属性来定位元素,使用find_element_by_name方法。
  3. 按Class Name定位:通过元素的class属性来定位元素,使用find_element_by_class_name方法。
  4. 按Xpath定位:使用find_element_by_xpath方法。

  1. 按CSS Selector定位:通过元素的CSS选择器来定位元素,使用find_element_by_css_selector方法。
  2. 按元素内容定位:通过元素的文本内容来定位元素,使用find_element_by_link_text或find_element_by_partial_link_text等方法。

Appium定位元素的方法有哪些( Xpath规则需要注意 )?

  • 通过 ID 定位

    • 使用方法 :使用 driver.find_element_by_id() 或者 MobileBy.ID

      • 例如

        • loc = (MobileBy.ID, 'com.wm.dmall:id/tv_positive') 或者 driver.find_element_by_id('com.wm.dmall:id/tv_positive')
    • 适用场景 :当目标元素有唯一且明确的 resource-id 时使用,这种方法是首选的定位方式之一,因为 ID 具有唯一性,定位准确且高效。

  • 通过 class_name 定位

    • 使用方法 :使用 driver.find_elements_by_class_name('android.widget.TextView')[1] 等。不过由于同一页面可能存在多个相同 class 的元素,所以一般结合下标来指定具体某一个元素。
    • 适用场景 :适用于页面中存在多个相同类名的元素,且需要定位到特定位置的元素时,但当下标发生变化时,定位可能会不准确。
  • 通过 accessibility_id 定位

    • 使用方法

      • 使用 driver.find_element_by_accessibility_id() 或者 MobileBy.ACCESSIBILITY_ID
      • 例如, driver.find_element_by_accessibility_id("accessibility_id值")loc = (MobileBy.ACCESSIBILITY_ID, 'accessibility_id值')
    • 适用场景 :对于支持可访问性的应用,当元素的 content-desc 属性值唯一时,可以使用此方法进行快速稳定的定位。

  • 通过 android_uiautomator 定位

    • text 文本定位语法

      • 使用 text 文本定义

        • loc_text = 'new UiSelector().text("登录/注册")' ,然后 driver.find_element_by_android_uiautomator(loc_text).click()
      • uiautomator text 模糊定位

        • 当文本较长时,可以使用 textContains 进行模糊匹配,
        • loc_text = 'new UiSelector().textContains("登录/注册")' ,然后 driver.find_element_by_android_uiautomator(loc_text).click()
      • textMatches 正则匹配查找

        • 通过正则表达式进行查找定位,
        • loc_text = 'new UiSelector().textMatches("^登录/.*")' ,然后 driver.find_element_by_android_uiautomator(loc_text).click()
      • textStartsWith 以某个文本开头匹配

        • loc_text = 'new UiSelector().textStartsWith("登录")' ,然后 driver.find_element_by_android_uiautomator(loc_text).click()
    • resourceId 定位

      • resourceId 定位

        • 和 appium 封装好的 id 定位类似,只是写法变成了 uiautomator 的写法,如
        • oc_id = 'new UiSelector().resourceId("com.wm.dmall:id/net_image_view ")' ,然后 driver.find_element_by_android_uiautomator(loc_id).click()
    • className 定位 :页面上的 class 属性一般不唯一,多半用在复数定位时候,比如通过 class 属性定位 “同意” 这个按钮下标就是 1。

  • 通过 XPath 定位

    • 使用方法 :使用 driver.find_element_by_xpath() 。例如, driver.find_element_by_xpath('//*ele[@class='android.widget.ImageView']')
    • Xpath定位兄弟元素如何处理?
  • 在Appium中,可以使用XPath轴定位来定位兄弟元素。以下是一些可以使用的XPath轴:

    • following-sibling:表示当前元素之后的所有兄弟元素。
    • following-sibling::*:表示当前元素之后的所有同级元素。
    • preceding-sibling:表示当前元素之前的所有兄弟元素。
    • preceding-sibling::*:表示当前元素之前的所有同级元素。
  • 例如,如果要定位一个元素的下一个兄弟元素(即后继兄弟元素),可以使用以下XPath表达式:

//xpath/for/the/current/element/following-sibling::tagName
  • 其中, tagName 是要定位的兄弟元素的标签名称。
  • 另外,如果要定位一个元素的上一个兄弟元素(即前驱兄弟元素),可以使用以下XPath表达式:
//xpath/for/the/current/element/preceding-sibling::tagName
  • 比如下面: 0-11互为兄弟元素

  • 我想通过 android.view.ViewGroup[0] 找到 android.view.ViewGroup[1] 里面的元素如何写?
  • 写法如下:

  • 完整XPATH:
"//android.widget.TextView[@resource-id='com.arashivision.insta360akiko:id/setting_item_title']/../../../../preceding-sibling::android.view.ViewGroup[2]"

说几个你知道的adb常用命令?

面试重点记忆: 装包,卸载包,抓日志,获取手机性能信息如CPU,内存,分辨率,拉/推文件到电脑等.

  1. adb devices - 显示当前连接的设备列表
  2. adb install <path_to_apk> - 安装应用程序
  3. adb uninstall <package_name> - 卸载应用程序
  4. adb pull <remote_path> <local_path> - 从设备中拉取文件
  5. adb push <local_path> <remote_path> - 将文件推送到设备中
  6. adb logcat - 查看设备的日志输出
  7. adb reboot - 重启设备
  8. adb shell pm list packages - 列出设备上安装的所有应用程序包名
  9. adb shell input keyevent <key_code> - 发送按键事件到设备。

IOS自动化工具呢,WDA/Tidevice命令了解嘛?

tidevice是一个用于管理iOS设备的命令行工具,常用命令包括:

  1. tidevice list --json:列出连接到计算机的所有iOS设备的信息。
  2. tidevice install :安装一个iOS应用程序。
  3. tidevice uninstall :卸载一个iOS应用程序。
  4. tidevice screenshot :在iOS设备上截图并保存到指定路径。
  5. tidevice logcat:查看iOS设备的日志信息。
  6. tidevice crashlog:查看iOS设备的崩溃日志。
  7. tidevice reboot:重启iOS设备。
  8. tidevice shutdown:关闭iOS设备。
  9. tidevice pair:配对iOS设备。
  10. tidevice mount:挂载iOS设备的文件系统。

Selenium 三种等待

Selenium的三大等待是什么?

  1. 隐式等待 指定一个时间,Selenium将在查找元素时等待一定的时间,如果在指定的时间内找到了元素,则继续执行, 如果超过了指定时间仍未找到元素,则抛出NoSuchElementException异常
browser.implicately_wait(秒数)

2. 显式等待: 在查找元素时,根据条件等待一定的时间,等待条件成立后再继续执行,可以指定等待的最长时间和轮询周期。

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
 
#最多等待10秒直到元素出现
#等待时间内没有找到元素超时会抛出TimeoutException
WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.XPATH,'')))
 
#还可以等待这个元素不出现
WebDriverWait(browser, 10).until_not(EC.presence_of_element_located((By.XPATH,'')))
#等待时间内找到元素超时会抛出TimeoutException
 
#二者唯一的区别是until和until_not
  1. 强制等待:比较稳定 ,线程停止,等待固定时间之后再执行脚本

    time.sleep(秒数)

    简单描述一下Pytest编写用例的规则:(选择性讲几个自己熟悉知道的即可~)

  2. 用例文件以test_开头并以.py结尾,如test_example.py。

  3. 用例函数以test_开头,并且使用驼峰命名规则,如test_login_success。

  4. 在用例函数中使用断言来验证测试结果,确保代码的正确性。

  5. 使用@pytest.fixture装饰器定义fixture函数,用来管理用例之间的依赖关系和共享资源。

  6. 使用@pytest.mark.parametrize装饰器来定义参数化测试用例,提高代码的复用性和可读性。

  7. 使用@pytest.mark.skip装饰器来跳过某些执行失败的用例,以便于调试和维护。

  8. 使用@pytest.mark.xfail装饰器来标记预期失败的用例,以便于后续修复和验证。

  9. 使用@pytest.mark.timeout装饰器来设置用例执行的超时时间,避免测试用例无限执行导致阻塞。

  10. 使用@pytest.mark.dependency装饰器来定义用例之间的依赖关系,保证用例的执行顺序和正确性。

讲一下pytest常见命令行参数的含义?

参数描述示例
-v , --verbose增加测试输出的详细程度,显示每个测试用例的详细信息,包括每个测试用例的执行情况(通过、失败等)以及测试用例的名称。pytest -v
-q , --quiet减少测试输出的详细程度,只显示测试用例的执行结果(通过或失败的数量),不显示具体的测试用例名称。pytest -q
-s , --capture=no禁用输出捕获,允许测试用例中的打印输出(如 print 语句)直接显示在控制台,而不是被捕获和隐藏。pytest -s
-x , --exitfirst一旦遇到第一个失败的测试用例,立即停止测试执行,不再继续执行后续的测试用例。pytest -x
--maxfail=num设置允许的最大失败测试用例数量,当失败的测试用例数量达到这个值时,停止测试执行。pytest --maxfail=2
-k expression只运行名称与给定表达式匹配的测试用例,表达式可以是测试用例名称的部分内容,支持模糊匹配。pytest -k "test_add"
-m marker只运行带有指定标记的测试用例,标记是使用 @pytest.mark 装饰器添加的。pytest -m "slow"
--lf , --last-failed只重新运行上一次失败的测试用例,方便快速定位和修复问题。pytest --lf
--ff , --failed-first首先运行上一次失败的测试用例,然后再运行其他测试用例。pytest --ff
--durations=N显示执行时间最长的 N 个测试用例,帮助找出执行时间较长的测试用例,以便进行优化。pytest --durations=5
--html=path生成 HTML 格式的测试报告, path 是报告文件的保存路径。pytest --html=report.html
--cov=module_path测量指定模块或包的代码覆盖率, module_path 是模块或包的路径。pytest --cov=my_module
-n num并行运行测试用例, num 是并行运行的进程数,需要安装 pytest-xdist 插件。pytest -n 4
--junitxml=path生成 JUnit XML 格式的测试报告, path 是报告文件的保存路径,常用于与持续集成工具集成。pytest --junitxml=test_report.xml

这些参数可以根据需要组合使用,以满足不同的测试需求。

例如, pytest -v -s --html=report.html 表示以详细模式运行测试,显示测试用例的输出,并生成 HTML 测试报告。

面试官:大致讲一下你知道的pytest的插件有哪些?

1. pytest-xdist

  • 功能 :支持分布式测试,允许你在多个 CPU 或多个主机上并行运行测试,大大加快测试套件的执行速度,尤其是对于大型测试套件非常有用。
  • 安装
pip install pytest-xdist
  • 使用示例
pytest -n 4  # 使用 4 个 CPU 核心运行测试

2. pytest-cov

  • 功能 :用于测量测试代码覆盖率,帮助你确定测试用例覆盖了代码的哪些部分,哪些部分还未被测试。
  • 安装
pip install pytest-cov
  • 使用示例 :命令行增加
pytest --cov=your_module_name  # 测量 your_module_name 的代码覆盖率

3. pytest-html

  • 功能 :生成 HTML 测试报告,方便查看测试结果和测试历史,提供直观的测试报告,包括测试用例的执行情况、通过和失败的信息等。
  • 安装
pip install pytest-html
  • 使用示例
pytest --html=report.html  # 生成名为 report.html 的测试报告

4. pytest-repeat

  • 功能 :可以多次重复执行测试用例,对于需要多次运行相同测试用例的情况很有用,例如测试某些具有随机性的功能时,以确保测试结果的一致性。
  • 安装
pip install pytest-repeat
  • 使用示例
pytest --count=3  # 重复每个测试用例 3 次

5. pytest-timeout

  • 功能 :为测试用例设置超时时间,如果测试用例执行时间超过设定的超时时间,会自动终止测试并标记为失败,避免长时间运行的测试用例导致测试流程的阻塞。
  • 安装
pip install pytest-timeout
  • 使用示例
pytest --timeout=30  # 设置超时时间为 30 秒

6. pytest-mock

  • 功能 :提供方便的 mock 功能,允许你在测试中模拟对象和函数,便于测试代码的不同部分,而不受外部依赖的影响。
  • 安装
pip install pytest-mock
  • 使用示例
def test_something(mocker):
    mock_func = mocker.patch('your_module.your_function')
    # 调用被测试的代码
    # 验证 mock 函数是否被调用
    mock_func.assert_called_once()

7. pytest-forked

  • 功能 :使用 fork 方式运行测试用例,避免测试用例之间的副作用,每个测试用例在独立的进程中运行,确保测试用例之间的独立性。
  • 安装
pip install pytest-forked

什么是CI/CD,有了解过嘛?

CI/CD是

持续集成(Continuous Integration)和

持续交付/持续部署(Continuous Delivery/Continuous Deployment)的缩写。

持续集成是指将开发人员对代码的更改频繁地集成到共享存储库中,并通过自动化构建和测试过程来验证代码的正确性。通过持续集成,开发团队可以更早地发现和解决代码集成问题,确保代码质量。

持续交付是指通过自动化的构建、测试和部署流程,将应用程序的代码交付给测试、预发布和生产环境,以便让产品团队、测试团队和客户能够快速获取最新的可部署版本。

持续部署是持续交付的进一步延伸,指在经过一系列自动化测试和验证之后,将代码自动部署到生产环境中,实现从代码提交到生产环境上线的全自动化过程。

通过CI/CD实践,团队可以实现代码构建、测试和部署的自动化,提高软件交付的速度、质量和可靠性,从而更快地响应用户需求、减少错误和故障,以及增强团队的协作和效率。

如何通过Jenkins流水线做CI/CD?

最好购买一台Linux云服务器,这样用来跑我们的Jenkins流水线任务方便(jenkins流水线配置教程如下):

知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具

面试差不多按照下面的话术来说即可,主要能答出Jenkins的作用,工作流程等。

Jenkins流水线是Jenkins提供的一种构建Pipeline的方式,可以通过将多个阶段(stage)组合在一起,实现复杂的CI/CD流程。以下是使用Jenkins流水线实现CI/CD的一般步骤:

  1. 创建Jenkins Pipeline:在Jenkins中创建一个新的Pipeline项目,并配置Pipeline的代码存放库(如Git、SVN等)和Jenkinsfile。

  2. 编写Jenkinsfile:Jenkinsfile是Pipeline的代码定义文件,其中包含Pipeline的各个阶段(stage)和具体步骤(step),可以使用Groovy语言编写。

  3. 定义Pipeline阶段:在Jenkinsfile中定义Pipeline的各个阶段,如代码拉取、编译、单元测试、集成测试、打包、部署等。

  4. 添加Pipeline步骤:在每个阶段中定义具体的步骤,如执行Shell命令、调用外部工具、触发其他Jenkins任务等。

  5. 实现自动化测试:在Pipeline中包含自动化测试的阶段,确保每次代码提交后自动执行测试并生成测试报告。

  6. 集成静态代码分析:在Pipeline中集成代码静态分析工具,如SonarQube,用于检测代码质量和安全漏洞。

  7. 定义部署阶段:在Pipeline中定义部署到各个环境(如测试、预发布、生产)的阶段,确保代码从提交到部署的自动化流程。

  8. 集成通知和报警:在Pipeline中集成通知插件,如Email、Slack等,以及报警系统,实现在出现问题时及时通知相关人员。

  9. 触发Pipeline:通过钩子(webhook)、定时器、手动触发等方式,触发Jenkins Pipeline的执行,实现自动化的CI/CD流程。

  10. 监控和优化:持续监控Pipeline的执行情况和结果,优化流程和效率,保持CI/CD流水线的稳定和高效运行。

Groovy语法及Jenkins流水线解读

1. 概述

Groovy 是一种基于 JVM(Java 虚拟机)的敏捷开发语言,它结合了 Python、Ruby 和 Smalltalk 的许多强大特性。

Groovy 可以与 Java 代码无缝集成,并且能在 Java 平台上轻松运行,既可以作为脚本语言使用,也可以用于开发大型应用程序。

它在 Jenkins 流水线、Gradle 构建脚本等场景中得到了广泛应用。

  1. 主要特点

2.1 语法简洁

Groovy 继承了 Java 的语法结构,但在此基础上进行了简化,减少了许多样板代码。

例如,定义类和方法时可以省略一些修饰符和分号。

// Java 定义类和方法
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

// Groovy 定义类和方法
class HelloWorld {
    static void main(args) {
        println 'Hello, World!'
    }
}

2.2 动态类型

Groovy 支持动态类型,这意味着在声明变量时不需要显式指定类型,变量的类型会在运行时自动确定。

def message = "Hello, Groovy!"
println message.class // 输出: class java.lang.String

2.3 闭包支持

闭包是 Groovy 的一个强大特性,它是一段可执行的代码块,可以作为参数传递给方法,也可以作为返回值返回。

闭包可以访问其定义时所在的上下文环境。

def greet = { name -> println "Hello, $name!" }
greet("John") // 输出: Hello, John!

2.4 字符串处理灵活

Groovy 提供了多种字符串表示方式,并且支持字符串插值。

def singleQuoted = 'This is a single-quoted string'
def doubleQuoted = "This is a double-quoted string with variable: ${singleQuoted}"
println doubleQuoted // 输出: This is a double-quoted string with variable: This is a single-quoted string

2.5 与 Java 无缝集成

Groovy 可以直接使用 Java 类和库,并且可以在 Groovy 代码中调用 Java 方法。

反之,Java 代码也可以调用 Groovy 代码。

import java.util.ArrayList

def list = new ArrayList()
list.add("element1")
println list.size() // 输出: 1

3. 基本语法

3.1 变量定义

使用 def 关键字定义动态类型变量,也可以显式指定类型。

def number = 10
int anotherNumber = 20

3.2 类和对象

Groovy 中的类定义与 Java 类似,但可以更简洁。

class Person {
    String name
    int age

    void introduce() {
        println "My name is $name and I'm $age years old."
    }
}

def person = new Person(name: "Alice", age: 25)
person.introduce() // 输出: My name is Alice and I'm 25 years old.

3.3 方法定义

方法定义可以省略返回类型和访问修饰符。

def add(a, b) {
    return a + b
}

def result = add(3, 5)
println result // 输出: 8

3.4 控制结构

Groovy 支持常见的控制结构,如 if-elseforwhile 等。

def num = 10
if (num > 5) {
    println "Number is greater than 5"
}

for (i in 1..5) {
    println i
}

def count = 0
while (count < 3) {
    println count
    count++
}

4. 在 Jenkins 流水线中的应用

在 Jenkins 流水线中,Groovy 被用于定义流水线的逻辑和步骤。例如:

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                echo 'Building the project...'
            }
        }
        stage('Test') {
            steps {
                sh 'mvn test' // 执行 Maven 测试命令
            }
        }
        stage('Deploy') {
            steps {
                sh 'mvn deploy' // 执行 Maven 部署命令
            }
        }
    }
}

在这个例子中,整个 Jenkins 流水线的定义就是一个 Groovy 脚本,通过 pipelinestagesteps 等关键字来组织和描述软件交付的各个阶段和操作

这段代码是一个使用 Jenkins 持续集成工具编写的 Pipeline 脚本:

  • pipline

    • 定义了整个 Jenkins 流程, PipelineJenkins 2.x 版本引入的一种基于代码的方式来定义和配置 CI/CD 流程的语法。
    • 它允许用户使用 Groovy 语言编写一系列的步骤,这些步骤将按照特定的顺序执行,从而实现自动化的构建、测试、部署等流程。
  • agent any

    • 指定了执行 Pipeline 的代理,可以是 Jenkins 集群中的任何一个节点。
    • 这里的 any 表示可以是任何可用的代理节点。
  • stages

    • 定义了 Pipeline 中的阶段,其中包含了任务的不同步骤。
    • 每个阶段都是一个独立的步骤单元,可以包含一个或多个步骤。
  • stage('Hello')

    • 创建了一个名为 Hello 的阶段。这个阶段将包含后续步骤的执行。
  • steps

    • 列出了 Hello 阶段中的具体步骤。在这个阶段中,只有一个步骤:
  • echo 'Hello World'

    • 在控制台输出 Hello World 。这通常用于调试或作为流程中的一个标记。

总结来说,这个 Pipeline 的工作流程如下:

  1. Jenkins 选择一个可用的代理来执行 Pipeline
  2. 执行 Hello 阶段。
  3. Hello 阶段中,打印 Hello World 到控制台。

Jenkins流水线常见命令解析,快速入门

JenkinsFile 是定义 Jenkins Pipeline 的文件,它使用 Groovy DSL 编写。

Jenkins Pipeline 是一种持续集成和持续交付(CI/CD)的工具,允许用户以代码的方式定义整个 CI/CD 流程。

  1. Pipeline 定义:JenkinsFile 必须以 pipeline 块开始和结束,定义了整个 Pipeline 的流程和阶段。
pipeline {
    // pipeline 定义和配置
}

2. 阶段(Stage)定义:阶段是 Pipeline 中的一个执行阶段,包含一系列的步骤(Step)。

stage('Build') {
    // 阶段相关的步骤
}

3. 步骤(Step)定义:步骤是 Pipeline 的最小执行单位,可以是 Shell 命令、Jenkins 插件、或者其他操作。

steps {
    sh 'mvn clean install'
}

4. 环境变量定义:可以在 JenkinsFile 中定义环境变量,供 Pipeline 中的步骤使用。

environment {
    JAVA_HOME = '/usr/lib/jvm/java-8-openjdk-amd64'
}

5. 条件判断:可以使用 when 来定义条件判断,根据条件执行不同的步骤。

steps {
    when {
        branch 'master'
    }
    sh 'echo "This is the master branch"'
}

6. Post 段:可以在 Pipeline 结束后定义一些后续的操作,比如发送通知或者清理资源。

post {
    always {
        echo 'Pipeline 完成'
    }
}

jenkins常见功能熟悉