地平线 嵌入式测试开发 二面 面经

1.自我介绍

面试官好,我是[姓名]。一面主要聊了项目细节和技术实现,这次我想从另一个角度介绍一下自己。

我对测试开发的理解是,它不只是发现bug,更重要的是保障质量、提升效率。在我的项目中,我既是开发者也是测试者,这让我深刻体会到测试的价值。开发时我会想"这个功能怎么实现",测试时我会想"这个功能会在什么情况下出问题",这种双重视角让我对软件质量有更深的理解。

我做过的最有价值的事情,是通过压力测试发现了系统的性能瓶颈,并提出了优化方案。这不只是发现问题,还要分析原因、给出建议,这才是测试开发的核心价值。

我选择测试开发这个方向,是因为它既有技术深度,又有业务价值。我希望能在这个领域深耕,用技术手段提升产品质量,用测试思维预防问题发生。

2.你认为测试开发和普通测试有什么区别?

我认为主要有几个方面的区别。

技术能力要求不同。普通测试主要是执行测试用例、发现bug、提交报告,技术要求相对较低。测试开发需要写代码,开发测试工具、搭建测试平台、分析测试数据,技术要求更高。比如性能测试,不只是跑JMeter脚本,还要分析性能瓶颈在哪里,是CPU、内存、IO还是网络,需要深入理解系统架构。

工作内容不同。普通测试更多是重复性工作,每个版本都要执行相同的测试用例。测试开发更多是创造性工作,开发自动化测试框架、设计测试方案、优化测试流程。比如我在项目中写了一个压力测试脚本,可以模拟不同数量的并发用户,这个脚本可以反复使用,大大提升了测试效率。

价值体现不同。普通测试的价值是发现bug,是质量的守门员。测试开发的价值是提升效率、预防问题,是质量的推动者。比如通过自动化测试,可以在每次代码提交时自动运行测试,及早发现问题;通过测试平台,可以让测试结果可视化,方便分析和决策。

职业发展不同。普通测试的天花板比较低,往上发展可能是测试主管、测试经理。测试开发可以往技术专家方向发展,也可以往架构师方向发展,职业路径更宽。

我选择测试开发,就是希望用技术手段解决测试中的问题,而不只是重复执行测试用例。

3.如果让你设计一个自动化测试框架,你会怎么设计?

我会从几个方面考虑。

首先是测试用例管理。需要一个统一的地方管理所有测试用例,包括用例的分类、优先级、执行频率等。可以用数据库存储,也可以用配置文件。我倾向于用YAML或JSON格式的配置文件,因为可读性好,也方便版本管理。

test_cases:
  - name: "用户登录测试"
    priority: high
    type: functional
    steps:
      - action: "输入用户名"
        data: "testuser"
      - action: "输入密码"
        data: "password123"
      - action: "点击登录"
      - action: "验证登录成功"
        expect: "欢迎页面"


其次是测试执行引擎。需要一个引擎来解析测试用例,执行测试步骤,收集测试结果。可以用Python实现,因为Python有丰富的测试库(pytest、unittest等)。执行引擎要支持并发执行,提高测试效率;要支持失败重试,提高测试稳定性;要支持断言机制,自动判断测试是否通过。

class TestExecutor:
    def execute_test_case(self, test_case):
        result = TestResult()
        try:
            for step in test_case.steps:
                self.execute_step(step)
            result.status = "PASS"
        except AssertionError as e:
            result.status = "FAIL"
            result.error = str(e)
        except Exception as e:
            result.status = "ERROR"
            result.error = str(e)
        return result


第三是测试报告生成。测试完成后要生成详细的报告,包括通过率、失败用例、错误信息、执行时间等。报告要可视化,最好是HTML格式,可以在浏览器中查看。还要支持趋势分析,对比不同版本的测试结果。

第四是持续集成。测试框架要能集成到CI/CD流程中,代码提交后自动触发测试。可以用Jenkins、GitLab CI等工具。测试失败时要能及时通知相关人员,可以通过邮件、钉钉、企业微信等方式。

第五是可扩展性。框架要支持不同类型的测试,比如接口测试、UI测试、性能测试等。可以用插件机制,不同类型的测试实现不同的插件。框架要提供统一的接口,插件只需要实现这些接口就可以集成进来。

class TestPlugin:
    def setup(self):
        pass
    
    def execute(self, test_case):
        pass
    
    def teardown(self):
        pass


最后是易用性。框架要简单易用,测试人员不需要太多编程知识就能使用。可以提供图形界面,拖拽式配置测试用例。也可以提供命令行工具,方便在服务器上运行。

4.你如何保证测试的覆盖率?如何设计测试用例?

测试覆盖率包括代码覆盖率和需求覆盖率两个方面。

代码覆盖率方面,我会使用覆盖率工具(如gcov、lcov)来统计。主要关注几个指标:行覆盖率(每行代码是否被执行)、分支覆盖率(每个if-else分支是否都测试到)、函数覆盖率(每个函数是否都被调用)。一般来说,核心模块的代码覆盖率要达到80%以上。

# 编译时开启覆盖率统计
g++ -fprofile-arcs -ftest-coverage main.cpp -o main

# 运行测试
./main

# 生成覆盖率报告
gcov main.cpp
lcov --capture --directory . --output-file coverage.info
genhtml coverage.info --output-directory coverage_report


需求覆盖率方面,我会根据需求文档设计测试用例,确保每个需求点都有对应的测试用例。可以用需求追溯矩阵来管理,每个需求对应哪些测试用例,每个测试用例覆盖哪些需求。

测试用例设计方面,我主要用这几种方法:

等价类划分:将输入分为有效等价类和无效等价类,每个等价类选一个代表值测试。比如年龄输入,有效等价类是1-120,无效等价类是负数、0、超过120、非数字等。

边界值分析:测试边界值和边界附近的值。比如年龄输入,测试0、1、120、121这些边界值。

场景法:根据业务场景设计测试用例。比如用户登录,场景包括:首次登录、重复登录、密码错误、账号不存在、网络异常等。

错误推测法:根据经验推测可能出错的地方。比如空指针、数组越界、并发冲突、内存泄漏等。

在我的项目中,我设计了这样的测试用例:

功能:用户登录
测试用例1:正常登录
  前置条件:用户已注册
  输入:正确的用户名和密码
  预期结果:登录成功,跳转到主页
  
测试用例2:密码错误
  前置条件:用户已注册
  输入:正确的用户名,错误的密码
  预期结果:提示密码错误,登录失败
  
测试用例3:用户不存在
  前置条件:无
  输入:不存在的用户名
  预期结果:提示用户不存在
  
测试用例4:空输入
  前置条件:无
  输入:用户名或密码为空
  预期结果:提示输入不能为空
  
测试用例5:SQL注入
  前置条件:无
  输入:用户名包含SQL语句(如:admin' OR '1'='1)
  预期结果:登录失败,不会被注入


通过这些方法,可以比较全面地覆盖各种场景,提高测试质量。

5.如何进行性能测试?如何定位性能瓶颈?

性能测试主要包括几个方面:响应时间、吞吐量、并发能力、资源占用。

响应时间测试,测量从发起请求到收到响应的时间。可以用curl命令测试单个请求,也可以用脚本测试多个请求的平均响应时间。

# 测试单个请求
curl -w "@curl-format.txt" -o /dev/null -s http://localhost:8080/api/login

# curl-format.txt内容
time_namelookup:  %{time_namelookup}\n
time_connect:  %{time_connect}\n
time_starttransfer:  %{time_starttransfer}\n
time_total:  %{time_total}\n


吞吐量测试,测量单位时间内能处理多少请求。可以用Apache Bench(ab)或wrk工具。

# 使用ab测试
ab -n 10000 -c 100 http://localhost:8080/api/login
# -n: 总请求数
# -c: 并发数

# 使用wrk测试
wrk -t 4 -c 100 -d 30s http://localhost:8080/api/login
# -t: 线程数
# -c: 连接数
# -d: 持续时间


并发能力测试,测量系统能支持多少并发用户。逐步增加并发数,观察系统的表现,找到系统的极限。

资源占用测试,监控CPU、内存、磁盘IO、网络IO等资源的使用情况。可以用top、htop、vmstat、iostat等工具。

# 监控CPU和内存
top -p $(pgrep myapp)

# 监控IO
iostat -x 1

# 监控网络
iftop -i eth0


定位性能瓶颈方面,我的方法是:

首先用性能分析工具找到热点函数。Linux下可以用perf,它能统计每个函数的CPU占用时间。

# 采样
perf record -g ./myapp

# 分析
perf report


然后分析热点函数的实现,看是否有优化空间。常见的性能问题包括:

  • 算法复杂度高:用O(n²)的算法,可以优化为O(n log n)或O(n)
  • 频繁的内存分配:可以用对象池或内存池
  • 不必要的拷贝:可以用引用或移动语义
  • 锁竞争:可以减小锁粒度或用无锁数据结构
  • IO阻塞:可以用异步IO或缓存

在我的项目中,我发现性能瓶颈在JSON解析,每个消息都要解析JSON,占用了大量CPU时间。优化方法是:

  1. 换用更快的JSON库(从nlohmann/json换到rapidjson)
  2. 缓存解析结果,相同的消息不重复解析
  3. 对于简单消息,用二进制协议代替JSON

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

嵌入式面试八股文全集 文章被收录于专栏

这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。

全部评论

相关推荐

评论
点赞
1
分享

创作者周榜

更多
正在热议
更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务