8.【学习】工业级详细接口约束&覆盖率

工业级详细接口约束&覆盖率模板

以下是4个最常用但之前未覆盖的核心接口 ,每个模板都包含:协议关键要点+完整事务类(含协议强制约束+错误注入+权重分布)+全面覆盖率收集器(含特殊场景覆盖)+最佳实践与常见陷阱


一、I2C 接口详细模板(v2.1 标准)

协议要点:两线串行总线,支持多主多从,7位/10位地址,标准模式(100kbps)/快速模式(400kbps)/高速模式(3.4Mbps)。

1. I2C 完整事务类(含所有约束)

c 复制代码
class i2c_transaction extends uvm_sequence_item;
  `uvm_object_utils(i2c_transaction)

  // 事务类型枚举
  typedef enum bit {READ, WRITE} i2c_dir_e;
  typedef enum bit [1:0] {STANDARD, FAST, HIGH_SPEED} i2c_speed_e;
  typedef enum bit {ACK, NACK} i2c_ack_e;

  // 随机变量
  rand bit [9:0]  slave_addr;      // 支持7位和10位地址
  rand bit        addr_10bit;      // 是否为10位地址模式
  rand i2c_dir_e  dir;             // 读写方向
  rand bit [7:0]  data[];          // 传输数据
  rand i2c_speed_e speed_mode;     // 速度模式
  rand int unsigned start_delay;   // 起始条件延时
  rand int unsigned byte_delay;    // 字节间延时
  rand int unsigned stop_delay;    // 停止条件延时
  
  // 错误注入变量
  rand bit        start_error;     // 起始条件错误
  rand bit        stop_error;      // 停止条件错误
  rand bit        ack_error;       // ACK错误
  rand bit        data_corrupt;    // 数据损坏
  rand int        corrupt_byte_idx;// 损坏的字节索引

  //==================== 协议强制约束 ====================
  constraint protocol_basic_c {
    // 地址约束
    if (addr_10bit == 1'b0) {
      slave_addr[9:7] == 3'b000; // 7位地址时高3位为0
    }
    
    // 数据长度约束
    data.size() inside {[1:256]}; // 单次传输最多256字节
    
    // 延时约束(根据速度模式调整)
    if (speed_mode == STANDARD) {
      start_delay inside {[4:10]};
      byte_delay inside {[4:10]};
      stop_delay inside {[4:10]};
    } else if (speed_mode == FAST) {
      start_delay inside {[1:3]};
      byte_delay inside {[1:3]};
      stop_delay inside {[1:3]};
    } else { // HIGH_SPEED
      start_delay inside {[0:1]};
      byte_delay inside {[0:1]};
      stop_delay inside {[0:1]};
    }
  }

  //==================== 错误注入约束 ====================
  constraint error_injection_c {
    // 默认无错误
    soft start_error == 1'b0;
    soft stop_error == 1'b0;
    soft ack_error == 1'b0;
    soft data_corrupt == 1'b0;
    
    // 错误概率控制
    start_error dist {0:=99, 1:=1};
    stop_error dist {0:=99, 1:=1};
    ack_error dist {0:=97, 1:=3};
    data_corrupt dist {0:=98, 1:=2};
    
    // 错误条件约束
    data_corrupt == 1'b1 -> corrupt_byte_idx inside {[0:data.size()-1]};
  }

  //==================== 权重分布约束 ====================
  constraint distribution_c {
    dir dist {READ:=50, WRITE:=50};
    addr_10bit dist {0:=90, 1:=10}; // 90%使用7位地址
    speed_mode dist {STANDARD:=60, FAST:=35, HIGH_SPEED:=5};
    data.size() dist {
      1:=20, [2:8]:=50, [9:32]:=20, [33:256]:=10
    };
  }

  //==================== 辅助函数 ====================
  function new(string name = "i2c_transaction");
    super.new(name);
  endfunction

  virtual function void do_print(uvm_printer printer);
    super.do_print(printer);
    printer.print_string("方向", dir.name());
    printer.print_field("从机地址", slave_addr, addr_10bit ? 10 : 7, UVM_HEX);
    printer.print_int("数据长度", data.size(), 8, UVM_DEC);
    printer.print_string("速度模式", speed_mode.name());
    if (start_error) printer.print_string("错误", "起始条件错误");
    if (stop_error) printer.print_string("错误", "停止条件错误");
    if (ack_error) printer.print_string("错误", "ACK错误");
    if (data_corrupt) printer.print_int("损坏字节索引", corrupt_byte_idx, 8, UVM_DEC);
  endfunction
endclass

2. I2C 全面覆盖率收集器

c 复制代码
class i2c_coverage extends uvm_subscriber #(i2c_transaction);
  `uvm_component_utils(i2c_coverage)

  i2c_transaction tr;

  covergroup i2c_cg;
    option.per_instance = 1;
    option.name = "i2c_full_coverage";
    option.comment = "I2C接口完整功能覆盖率";

    //==================== 基本功能覆盖 ====================
    cp_dir: coverpoint tr.dir {
      bins read = {i2c_transaction::READ};
      bins write = {i2c_transaction::WRITE};
    }

    cp_addr_mode: coverpoint tr.addr_10bit {
      bins addr_7bit = {1'b0};
      bins addr_10bit = {1'b1};
    }

    cp_speed_mode: coverpoint tr.speed_mode;

    cp_data_len: coverpoint tr.data.size() {
      bins len_1 = {1};
      bins len_2_8 = {[2:8]};
      bins len_9_32 = {[9:32]};
      bins len_33_128 = {[33:128]};
      bins len_129_256 = {[129:256]};
    }

    //==================== 错误场景覆盖 ====================
    cp_start_error: coverpoint tr.start_error;
    cp_stop_error: coverpoint tr.stop_error;
    cp_ack_error: coverpoint tr.ack_error;
    cp_data_corrupt: coverpoint tr.data_corrupt;

    //==================== 关键交叉覆盖率 ====================
    // 地址模式与读写方向的组合
    cross_addr_dir: cross cp_addr_mode, cp_dir;

    // 速度模式与数据长度的组合
    cross_speed_len: cross cp_speed_mode, cp_data_len;

    // 错误场景与读写方向的组合
    cross_error_dir: cross cp_dir, cp_start_error, cp_stop_error, cp_ack_error, cp_data_corrupt {
      // 忽略无错误的组合(已经被其他交叉覆盖)
      ignore_bins no_error = (binsof(cp_start_error) intersect {0} && 
                             binsof(cp_stop_error) intersect {0} && 
                             binsof(cp_ack_error) intersect {0} && 
                             binsof(cp_data_corrupt) intersect {0});
    }

    // 10位地址与高速模式的组合(容易出问题的场景)
    cross_10bit_highspeed: cross cp_addr_mode, cp_speed_mode {
      bins addr10bit_highspeed = binsof(cp_addr_mode.addr_10bit) && 
                                binsof(cp_speed_mode.HIGH_SPEED);
    }
  endgroup

  function new(string name = "i2c_coverage", uvm_component parent = null);
    super.new(name, parent);
    i2c_cg = new();
  endfunction

  virtual function void write(i2c_transaction t);
    tr = t;
    i2c_cg.sample();
  endfunction
endclass

3. I2C 最佳实践与常见陷阱

  • 必须覆盖:7位/10位地址、所有速度模式、ACK/NACK、重复起始条件
  • 错误注入重点:ACK错误(最常见的通信问题)、起始/停止条件错误
  • 常见陷阱:忘记处理10位地址的特殊格式、高速模式下时序约束不正确
  • 💡 实用技巧:在monitor中额外添加一个covergroup来覆盖SCL和SDA的时序关系

二、I2S 接口详细模板(v2.1 标准)

协议要点:串行音频接口,用于连接音频编解码器,支持立体声/单声道、不同数据宽度、左对齐/右对齐/飞利浦标准格式。

1. I2S 完整事务类

c 复制代码
class i2s_transaction extends uvm_sequence_item;
  `uvm_object_utils(i2s_transaction)

  typedef enum bit [1:0] {PHILIPS, LEFT_JUSTIFIED, RIGHT_JUSTIFIED} i2s_format_e;
  typedef enum bit {STEREO, MONO} i2s_channel_e;
  typedef enum bit {TX, RX} i2s_dir_e;

  // 随机变量
  rand i2s_dir_e      dir;
  rand i2s_format_e   format;
  rand i2s_channel_e  channel_mode;
  rand int unsigned   data_width;    // 数据宽度(16/20/24/32位)
  rand int unsigned   sample_rate;   // 采样率(8k/16k/44.1k/48k/96k/192k Hz)
  rand bit [31:0]     left_data[];   // 左声道数据
  rand bit [31:0]     right_data[];  // 右声道数据
  rand int unsigned   sample_count;  // 采样点数
  rand int unsigned   clk_div;       // 时钟分频器
  
  // 错误注入
  rand bit            clk_error;     // 时钟错误
  rand bit            sync_error;    // 同步错误
  rand bit            data_mismatch; // 左右声道数据不匹配

  //==================== 协议强制约束 ====================
  constraint protocol_c {
    // 数据宽度约束
    data_width inside {16, 20, 24, 32};
    
    // 采样率约束
    sample_rate inside {8000, 16000, 44100, 48000, 96000, 192000};
    
    // 采样点数约束
    sample_count inside {[1:1024]};
    left_data.size() == sample_count;
    right_data.size() == sample_count;
    
    // 单声道模式约束
    if (channel_mode == MONO) {
      right_data == '{default:0}; // 单声道时右声道为0
    }
    
    // 时钟分频器约束(根据采样率和主时钟计算)
    clk_div inside {[1:256]};
  }

  //==================== 格式特定约束 ====================
  constraint format_specific_c {
    if (format == PHILIPS) {
      // 飞利浦格式:数据在第二个时钟沿开始
      data_width <= 32;
    } else if (format == LEFT_JUSTIFIED) {
      // 左对齐格式:数据在第一个时钟沿开始
      data_width <= 24;
    } else { // RIGHT_JUSTIFIED
      // 右对齐格式:数据在最后一个时钟沿结束
      data_width inside {16, 24};
    }
  }

  //==================== 错误注入约束 ====================
  constraint error_c {
    soft clk_error == 1'b0;
    soft sync_error == 1'b0;
    soft data_mismatch == 1'b0;
    
    clk_error dist {0:=99, 1:=1};
    sync_error dist {0:=98, 1:=2};
    data_mismatch dist {0:=97, 1:=3};
    
    data_mismatch == 1'b1 -> channel_mode == STEREO;
  }

  //==================== 权重分布约束 ====================
  constraint dist_c {
    dir dist {TX:=50, RX:=50};
    format dist {PHILIPS:=70, LEFT_JUSTIFIED:=20, RIGHT_JUSTIFIED:=10};
    channel_mode dist {STEREO:=80, MONO:=20};
    data_width dist {16:=60, 24:=30, 20:=8, 32:=2};
    sample_rate dist {44100:=40, 48000:=30, 16000:=15, 96000:=10, 8000:=4, 192000:=1};
    sample_count dist {[1:32]:=60, [33:128]:=30, [129:1024]:=10};
  }

  function new(string name = "i2s_transaction");
    super.new(name);
  endfunction
endclass

2. I2S 全面覆盖率收集器

c 复制代码
class i2s_coverage extends uvm_subscriber #(i2s_transaction);
  `uvm_component_utils(i2s_coverage)

  i2s_transaction tr;

  covergroup i2s_cg;
    option.per_instance = 1;

    cp_dir: coverpoint tr.dir;
    cp_format: coverpoint tr.format;
    cp_channel_mode: coverpoint tr.channel_mode;
    cp_data_width: coverpoint tr.data_width;
    cp_sample_rate: coverpoint tr.sample_rate;
    cp_sample_count: coverpoint tr.sample_count {
      bins small = {[1:32]};
      bins medium = {[33:128]};
      bins large = {[129:1024]};
    }

    // 错误覆盖
    cp_clk_error: coverpoint tr.clk_error;
    cp_sync_error: coverpoint tr.sync_error;
    cp_data_mismatch: coverpoint tr.data_mismatch;

    // 关键交叉覆盖率
    cross_format_width: cross cp_format, cp_data_width {
      // 过滤不支持的组合
      ignore_bins philips_32bit = binsof(cp_format.PHILIPS) && binsof(cp_data_width) intersect {32};
      ignore_bins left_32bit = binsof(cp_format.LEFT_JUSTIFIED) && binsof(cp_data_width) intersect {32};
      ignore_bins right_20bit = binsof(cp_format.RIGHT_JUSTIFIED) && binsof(cp_data_width) intersect {20, 32};
    }

    cross_format_channel: cross cp_format, cp_channel_mode;
    cross_rate_width: cross cp_sample_rate, cp_data_width;
    cross_error_format: cross cp_format, cp_sync_error, cp_data_mismatch;
  endgroup

  function new(string name = "i2s_coverage", uvm_component parent = null);
    super.new(name, parent);
    i2s_cg = new();
  endfunction

  virtual function void write(i2s_transaction t);
    tr = t;
    i2s_cg.sample();
  endfunction
endclass

三、CAN FD 接口详细模板(ISO 11898-2:2016)

协议要点:汽车电子标准接口,支持经典CAN和CAN FD格式,最高数据速率8Mbps,数据长度最多64字节。

1. CAN FD 完整事务类

c 复制代码
class can_fd_transaction extends uvm_sequence_item;
  `uvm_object_utils(can_fd_transaction)

  typedef enum bit {CLASSIC_CAN, CAN_FD} can_format_e;
  typedef enum bit [1:0] {DATA_FRAME, REMOTE_FRAME, ERROR_FRAME, OVERLOAD_FRAME} can_frame_type_e;
  typedef enum bit {ACK_SLOT, NO_ACK} can_ack_e;

  // 随机变量
  rand can_format_e      format;
  rand can_frame_type_e  frame_type;
  rand bit [28:0]        id;          // 标识符(11位标准或29位扩展)
  rand bit               ide;         // 扩展标识符位
  rand bit               rtr;         // 远程传输请求位
  rand bit               brs;         // 波特率切换位(仅CAN FD)
  rand bit               esi;         // 错误状态指示位(仅CAN FD)
  rand bit [3:0]         dlc;         // 数据长度码
  rand bit [7:0]         data[];      // 数据字段
  rand can_ack_e         ack_type;
  rand int unsigned      arbitration_baud; // 仲裁段波特率
  rand int unsigned      data_baud;      // 数据段波特率(仅CAN FD)
  
  // 错误注入
  rand bit               stuff_error;   // 位填充错误
  rand bit               crc_error;     // CRC错误
  rand bit               form_error;    // 格式错误
  rand bit               bit_error;     // 位错误

  //==================== 协议强制约束 ====================
  constraint protocol_basic_c {
    // 标识符约束
    if (ide == 1'b0) {
      id[28:11] == 18'b0; // 标准ID时高18位为0
    }
    
    // DLC与数据长度的映射
    if (format == CLASSIC_CAN) {
      dlc inside {[0:8]};
      data.size() == dlc;
    } else { // CAN_FD
      dlc inside {[0:15]};
      // CAN FD DLC到数据长度的映射
      (dlc == 0) -> data.size() == 0;
      (dlc == 1) -> data.size() == 1;
      (dlc == 2) -> data.size() == 2;
      (dlc == 3) -> data.size() == 3;
      (dlc == 4) -> data.size() == 4;
      (dlc == 5) -> data.size() == 5;
      (dlc == 6) -> data.size() == 6;
      (dlc == 7) -> data.size() == 7;
      (dlc == 8) -> data.size() == 8;
      (dlc == 9) -> data.size() == 12;
      (dlc == 10) -> data.size() == 16;
      (dlc == 11) -> data.size() == 20;
      (dlc == 12) -> data.size() == 24;
      (dlc == 13) -> data.size() == 32;
      (dlc == 14) -> data.size() == 48;
      (dlc == 15) -> data.size() == 64;
    }
    
    // 波特率约束
    arbitration_baud inside {125000, 250000, 500000, 1000000};
    if (format == CAN_FD && brs == 1'b1) {
      data_baud inside {1000000, 2000000, 4000000, 8000000};
      data_baud > arbitration_baud; // 数据段波特率必须高于仲裁段
    } else {
      data_baud == arbitration_baud;
    }
  }

  //==================== 帧类型特定约束 ====================
  constraint frame_type_c {
    if (frame_type == REMOTE_FRAME) {
      rtr == 1'b1;
      data.size() == 0; // 远程帧没有数据字段
    } else {
      rtr == 1'b0;
    }
    
    if (frame_type == ERROR_FRAME || frame_type == OVERLOAD_FRAME) {
      format == CLASSIC_CAN; // 错误帧和过载帧只有经典CAN格式
    }
  }

  //==================== 错误注入约束 ====================
  constraint error_injection_c {
    soft stuff_error == 1'b0;
    soft crc_error == 1'b0;
    soft form_error == 1'b0;
    soft bit_error == 1'b0;
    
    stuff_error dist {0:=98, 1:=2};
    crc_error dist {0:=97, 1:=3};
    form_error dist {0:=98, 1:=2};
    bit_error dist {0:=99, 1:=1};
    
    // 同一帧最多注入一种错误
    $countones({stuff_error, crc_error, form_error, bit_error}) <= 1;
  }

  //==================== 权重分布约束 ====================
  constraint dist_c {
    format dist {CLASSIC_CAN:=40, CAN_FD:=60};
    frame_type dist {DATA_FRAME:=85, REMOTE_FRAME:=10, ERROR_FRAME:=3, OVERLOAD_FRAME:=2};
    ide dist {0:=70, 1:=30}; // 70%使用标准ID
    brs dist {0:=30, 1:=70}; // 70%的CAN FD帧使用波特率切换
    dlc dist {
      0:=5, 1:=10, 2:=10, 3:=10, 4:=10, 5:=5, 6:=5, 7:=5, 8:=15,
      9:=5, 10:=5, 11:=3, 12:=3, 13:=3, 14:=3, 15:=3
    };
  }

  function new(string name = "can_fd_transaction");
    super.new(name);
  endfunction
endclass

2. CAN FD 全面覆盖率收集器

c 复制代码
class can_fd_coverage extends uvm_subscriber #(can_fd_transaction);
  `uvm_component_utils(can_fd_coverage)

  can_fd_transaction tr;

  covergroup can_fd_cg;
    option.per_instance = 1;

    // 基本覆盖
    cp_format: coverpoint tr.format;
    cp_frame_type: coverpoint tr.frame_type;
    cp_ide: coverpoint tr.ide;
    cp_brs: coverpoint tr.brs;
    cp_esi: coverpoint tr.esi;
    cp_dlc: coverpoint tr.dlc;
    cp_ack_type: coverpoint tr.ack_type;

    // 波特率覆盖
    cp_arbitration_baud: coverpoint tr.arbitration_baud;
    cp_data_baud: coverpoint tr.data_baud;

    // 错误覆盖
    cp_stuff_error: coverpoint tr.stuff_error;
    cp_crc_error: coverpoint tr.crc_error;
    cp_form_error: coverpoint tr.form_error;
    cp_bit_error: coverpoint tr.bit_error;

    // 关键交叉覆盖率
    cross_format_dlc: cross cp_format, cp_dlc {
      // 过滤经典CAN不支持的DLC
      ignore_bins classic_dlc_9_15 = binsof(cp_format.CLASSIC_CAN) && 
                                    binsof(cp_dlc) intersect {[9:15]};
    }

    cross_format_baud: cross cp_format, cp_brs, cp_data_baud {
      ignore_bins classic_brs = binsof(cp_format.CLASSIC_CAN) && binsof(cp_brs) intersect {1};
      ignore_bins no_brs_high_baud = binsof(cp_brs) intersect {0} && 
                                    binsof(cp_data_baud) intersect {2000000, 4000000, 8000000};
    }

    cross_frame_error: cross cp_frame_type, cp_stuff_error, cp_crc_error, cp_form_error, cp_bit_error;
    cross_id_format: cross cp_ide, cp_format;
  endgroup

  function new(string name = "can_fd_coverage", uvm_component parent = null);
    super.new(name, parent);
    can_fd_cg = new();
  endfunction

  virtual function void write(can_fd_transaction t);
    tr = t;
    can_fd_cg.sample();
  endfunction
endclass

四、PCIe 基础事务详细模板(PCIe 3.0)

协议要点:高速串行总线,基于数据包传输,支持存储器读写、IO读写、配置读写等事务类型。

1. PCIe 存储器读写事务类

c 复制代码
class pcie_mem_transaction extends uvm_sequence_item;
  `uvm_object_utils(pcie_mem_transaction)

  typedef enum bit [2:0] {MRd, MWr, Cpl, CplD} pcie_tlp_type_e;
  typedef enum bit [2:0] {TC0, TC1, TC2, TC3, TC4, TC5, TC6, TC7} pcie_tc_e;

  // TLP头字段
  rand pcie_tlp_type_e  tlp_type;
  rand pcie_tc_e        tc;           // 流量类别
  rand bit [3:0]        tag;          // 标签
  rand bit [9:0]        length;       // 数据长度(DW为单位)
  rand bit [63:0]       addr;         // 地址
  rand bit [2:0]        attr;         // 属性字段
  rand bit [1:0]        ep;           // 中毒位和错误位
  rand bit [15:0]       requester_id; // 请求者ID
  rand bit [15:0]       completer_id; // 完成者ID(仅完成包)
  rand bit [31:0]       data[];       // 数据(DW为单位)
  
  // 控制字段
  rand int unsigned     payload_size; // 有效载荷大小
  rand bit              is_64bit_addr; // 是否为64位地址
  rand bit              with_data;    // 是否带数据

  //==================== 协议强制约束 ====================
  constraint protocol_basic_c {
    // 长度约束
    length inside {[1:1024]}; // 最大1024 DW
    data.size() == length;
    
    // 地址约束
    if (is_64bit_addr == 1'b0) {
      addr[63:32] == 32'b0; // 32位地址时高32位为0
    }
    addr[1:0] == 2'b00; // 地址4字节对齐
    
    // 事务类型约束
    if (tlp_type == MRd) {
      with_data == 1'b0; // 存储器读请求不带数据
    } else if (tlp_type == MWr) {
      with_data == 1'b1; // 存储器写请求带数据
    } else if (tlp_type == Cpl) {
      with_data == 1'b0; // 完成包不带数据
    } else if (tlp_type == CplD) {
      with_data == 1'b1; // 带数据完成包带数据
    }
  }

  //==================== 权重分布约束 ====================
  constraint dist_c {
    tlp_type dist {MRd:=40, MWr:=40, Cpl:=10, CplD:=10};
    tc dist {TC0:=90, TC1:=5, TC2:=3, [TC3:TC7]:=2}; // 大部分使用TC0
    is_64bit_addr dist {0:=60, 1:=40};
    length dist {
      1:=30, [2:8]:=40, [9:32]:=20, [33:128]:=8, [129:1024]:=2
    };
  }

  function new(string name = "pcie_mem_transaction");
    super.new(name);
  endfunction
endclass

2. PCIe 基础覆盖率收集器

c 复制代码
class pcie_coverage extends uvm_subscriber #(pcie_mem_transaction);
  `uvm_component_utils(pcie_coverage)

  pcie_mem_transaction tr;

  covergroup pcie_cg;
    option.per_instance = 1;

    cp_tlp_type: coverpoint tr.tlp_type;
    cp_tc: coverpoint tr.tc;
    cp_tag: coverpoint tr.tag;
    cp_length: coverpoint tr.length {
      bins len_1 = {1};
      bins len_2_8 = {[2:8]};
      bins len_9_32 = {[9:32]};
      bins len_33_128 = {[33:128]};
      bins len_129_1024 = {[129:1024]};
    }
    cp_addr_width: coverpoint tr.is_64bit_addr;
    cp_attr: coverpoint tr.attr;
    cp_ep: coverpoint tr.ep;

    // 关键交叉覆盖率
    cross_type_length: cross cp_tlp_type, cp_length;
    cross_type_addr: cross cp_tlp_type, cp_addr_width;
    cross_tc_type: cross cp_tc, cp_tlp_type;
  endgroup

  function new(string name = "pcie_coverage", uvm_component parent = null);
    super.new(name, parent);
    pcie_cg = new();
  endfunction

  virtual function void write(pcie_mem_transaction t);
    tr = t;
    pcie_cg.sample();
  endfunction
endclass

五、通用集成与使用指南

1. 快速集成步骤

  1. 将事务类文件复制到你的项目中
  2. 修改地址范围、数据长度等与你的DUT相关的参数
  3. 在driver中实现事务到信号的转换
  4. 在monitor中实现信号到事务的转换
  5. 将覆盖率收集器集成到agent中(参考之前的通用模板)
  6. 运行仿真,查看覆盖率报告,针对未覆盖的点编写定向测试用例

2. 通用最佳实践

  • 优先使用事务级覆盖率,而不是信号级覆盖率
  • 每个接口单独一个覆盖率收集器,便于维护和复用
  • 定期检查覆盖率报告,找出覆盖率收敛慢的点并调整约束
  • 错误场景覆盖率至少要达到90%以上,这是发现bug的关键
  • 不要过度追求100%覆盖率,有些场景在实际使用中永远不会出现
相关推荐
Chase_______1 小时前
【Java基础核心知识点全解·09】Java 内存布局与垃圾回收详解:栈、堆、栈帧、GC Roots 与对象回收
java·开发语言
江南十四行2 小时前
并发编程(四)
开发语言·python
星夜夏空992 小时前
FreeRTOS学习(6)——任务创建
单片机·嵌入式硬件·学习
葱卤山猪2 小时前
C++17 联合体
开发语言·c++
折哥的程序人生 · 物流技术专研2 小时前
Java 23 种设计模式:从踩坑到精通 | 抽象工厂 —— 支付/收款如何成套创建?跨平台 UI 如何一键换肤?
java·开发语言·后端·设计模式
方也_arkling2 小时前
【Java-Day11】抽象类和抽象方法
java·开发语言
Ulyanov2 小时前
深入QML-Python通信 构建响应式交互界面的桥梁设计:QML+PySide6现代开发入门(五)
开发语言·python·算法·交互·qml·系统仿真
就叫_这个吧2 小时前
JavaScript中常用事件示例展示附源码
开发语言·javascript·html
不会C语言的男孩2 小时前
C++ Primer Plus 第9章:内存模型和名称空间
开发语言·c++