第二章 自动化测试基础概念

各位同学好,我是老张。今天咱们聊聊自动化测试的基础概念。说实话,我见过太多人一上来就搞自动化,结果搞得一团糟。为什么?因为基础没打牢。这一章,我就把自动化测试的底裤给你扒干净。

什么是自动化测试

自动化测试,说白了就是用代码代替手工去执行测试。你想想看,一个剃须刀要测试开关机1000次,手动按得手都抽筋了。自动化测试就是写个脚本,让机器替你按这1000次。

我个人习惯把自动化测试分成三个层次:

  • 单元测试:测试单个函数、单个模块。比如测试一个电压读取函数是否返回正确值。
  • 集成测试:测试多个模块配合工作。比如测试电机驱动和PWM控制能否协同工作。
  • 系统测试:测试整个产品功能。比如模拟用户从开机到充电完成的全流程。

我在项目中遇到过最典型的例子:一个同事写了2000行测试代码,结果发现连最基本的GPIO初始化都没测到。嗯,这就是典型的「为了自动化而自动化」。

嵌入式测试的挑战

嵌入式测试和纯软件测试不一样。为什么?因为嵌入式系统有硬件!我刚开始做嵌入式测试时,觉得和Web测试差不多,结果被现实狠狠打脸。

嵌入式测试的主要挑战有:

挑战 说明 我的经验
硬件依赖 测试必须依赖真实硬件或仿真器 我曾经因为仿真器驱动版本不对,浪费了整整两天
资源受限 MCU内存小、Flash小,跑不了大型测试框架 我建议用轻量级框架,比如Unity、CMock
实时性要求 很多功能有严格的时间约束 比如PWM波形必须精确到微秒级
调试困难 出问题很难定位是硬件还是软件 我习惯先隔离硬件,用模拟器跑一遍
避坑指南: 我曾经接手过一个项目,测试代码里直接操作了硬件寄存器。结果换了一个芯片型号,所有测试全部失效。记住:测试代码也要考虑可移植性!

自动化测试 vs 手动测试

很多新手问我:「老张,是不是自动化测试能完全替代手动测试?」我的回答是:想得美!

咱们来对比一下:

  • 自动化测试的优势
    • 跑得快:一秒能跑几百个测试用例
    • 重复性好:每次执行结果一致
    • 适合回归测试:改完代码一键跑
  • 手动测试的优势
    • 探索性强:能发现意想不到的问题
    • 适合用户体验测试:比如剃须刀握持手感
    • 初期成本低:不用写代码

我个人习惯是:核心功能用自动化,边缘场景用手动。举个例子,剃须刀的电机启停功能,我肯定写自动化脚本跑1000次。但用户实际使用时的各种奇葩操作,比如一边充电一边用,这种我建议手动测一测。

小技巧: 我建议把自动化测试和手动测试的比例控制在7:3左右。自动化覆盖核心功能,手动覆盖异常场景。这样既高效又全面。

测试金字塔模型

测试金字塔这个概念,说白了就是告诉你测试应该怎么分层。我见过太多人把精力全放在UI测试上,结果底层逻辑一堆bug。你想想看,地基都没打好,装修再漂亮有什么用?

经典的测试金字塔分三层:

  1. 底层:单元测试(占比约70%)

    这是金字塔的基石。测试单个函数、单个模块。比如测试一个计算电池电量的函数:

    // 测试电池电量计算函数
    void test_battery_level(void) {
        // 输入电压3.7V,应该返回100%
        TEST_ASSERT_EQUAL(100, calculate_battery_level(3.7));
        
        // 输入电压3.0V,应该返回0%
        TEST_ASSERT_EQUAL(0, calculate_battery_level(3.0));
        
        // 输入电压3.3V,应该返回50%
        TEST_ASSERT_EQUAL(50, calculate_battery_level(3.3));
    }
  2. 中间层:集成测试(占比约20%)

    测试多个模块的配合。比如测试电机驱动和PWM控制能否协同工作:

    // 测试电机启动流程
    void test_motor_start(void) {
        // 设置PWM占空比为50%
        pwm_set_duty(50);
        
        // 启动电机
        motor_start();
        
        // 验证电机转速是否在预期范围内
        uint32_t speed = motor_get_speed();
        TEST_ASSERT_TRUE(speed > 1000 && speed < 2000);
    }
  3. 顶层:系统测试(占比约10%)

    测试整个产品功能。比如模拟用户操作全流程:

    // 测试用户完整使用流程
    void test_user_scenario(void) {
        // 1. 按下电源键
        press_power_button();
        delay_ms(100);
        
        // 2. 验证电机启动
        TEST_ASSERT_TRUE(motor_is_running());
        
        // 3. 使用5秒后关机
        delay_ms(5000);
        press_power_button();
        
        // 4. 验证电机停止
        TEST_ASSERT_FALSE(motor_is_running());
    }
核心要点: 测试金字塔告诉我们,底层测试要写得多,顶层测试要写得少。我见过最离谱的项目,系统测试写了500个用例,单元测试只有20个。结果每次改代码,系统测试跑一遍要3小时,而且出了问题还不好定位。后来我帮他们重构,把重心放到单元测试上,问题定位效率提升了10倍。

嗯,这一章的内容就到这里。记住:自动化测试不是万能药,但用好了绝对是利器。下一章咱们聊聊嵌入式测试框架的选择,我会分享一些我踩过的坑和总结的经验。