《软件测试技术实战:设计、工具及管理》—第2章 2.6节软件白盒测试

简介: 白盒测试不仅在单元测试时进行,也可以在系统测试时进行,最早在嵌入式软件测试中,通过插桩的技术,通过工具得知各种覆盖率达到百分之几。

本节书摘来自异步社区《软件测试技术实战:设计、工具及管理》一书中的第2章,第2.6节软件白盒测试,作者顾翔,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.6 软件白盒测试
上面介绍的5个测试用例的设计方法大部分都适用于黑盒测试。下面让我们来详细介绍软件白盒测试的一些知识。先来看一下由Main Cohn提出的著名的软件测试金字塔,如图2-14所示。


7ad91b0ff3e676de14b1264b9130176fe5893a31

由于白盒测试是单元测试的主要内容,所以白盒测试在整个软件测试过程中很重要。

白盒测试覆盖包括语句覆盖、分支覆盖、条件覆盖、分支/条件覆盖、MC/DC(修订的条件/判定)覆盖、路径覆盖、控制流覆盖等,这些是白盒测试技术中基本的概念,将在本节中详细介绍。在介绍之前,看一下本节中将要用到的一个程序,如图2-15所示。


d3cde9c8f123c928483adf1989b3065558306013

这里包括如下。

 3个语句:S1、S2、S3。

 2个判断:M1、M2。

 4条路径:L1:ace、L2:abe、L3:acd、L4:abd。

 8个条件:T1:x>3、T2:z<10、T3:x=4、T4:y>5、F1:x<=3、F2:j>=10、F3:x<>4、F4:y>=5。

2.6.1 语句覆盖测试
语句覆盖(Statement Coverage)又叫行覆盖(Line Coverage)。段覆盖(Segment Coverage)。基本块覆盖(Basic Block Coverage),这是最常用、也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了。这里说的是“可执行语句”,因此就不会包括像C++的头文件声明、代码注释、空行等。非常好理解,只统计能够执行的代码被执行了多少行。需要注意的是,单独一行的花括号{}也常常被统计进去。语句覆盖常常被人指责为“最弱的覆盖”,它只覆盖代码中的执行语句,不考虑各种分支的组合等。假如只要求达到语句覆盖,那么换来的测试效果的确不明显,很难发现代码中更多的问题。

语句覆盖率的公式可以表示如下。

语句覆盖率=被评价到的语句数量/可执行的语句总数×100%。

下面让我们来看看各种情况下的语句覆盖。

在顺序语句中语句覆盖:在顺序语句中,语句覆盖率最简单,只要把顺序语句中的每个语句都覆盖到。

int f (int a,int b){
int c;
c=a+b;
return c;
}

语句覆盖率100%测试用例:f(1,2)。

在没有else的判断语句中语句覆盖:只要执行if语句中的内容就可以了。

int f (int a){
int b=0;
if (a>0){
   b=1;
   }
return b;
}

语句覆盖率100%测试用例:f(1)。

在有else的判断语句中语句覆盖:既要执行if语句,也要执行else中的语句。

int f (int a){
int b=0;
  if (a>0){
    b=1;
  } else{
    b=2;
  }
return b;
}

语句覆盖率100%测试用例:f(1)(执行了b=1语句)、f(0)(执行了b=2语句)两个。

在循环语句中语句覆盖:循环体内的语句必须有且有一次被运行。

int f (int a){
for (i=0;i<=a;i++)
     …
     printf(“hello”,s);
     …
}

语句覆盖率100%测试用例:f(0)。这里需要特别强调的是:测试用例在循环体内语句,必须有且有一次被运行,是因为循环体内的语句可能很长,如果让它执行2次,10次,甚至50次,100次或更多次,这样单元测试的时间会变得很长,而且意义不大。另外,单元测试要求一个测试用例最好在0.5s内能够执行完毕。

在多条件语句中语句覆盖:每一个分支必须执行一次。

int f (int a){ 
        switch (a) {
        case:1 { f1(); break;}
        case:2 { f2(); break;}
        case:3 { f3(); break;}
        case:4 { f4(); break;}
}

语句覆盖率100%测试用例:f(1)、f(2)、f(3)、f(4) 共4个。

看看在开始的例子中,设计哪些数据可以达到语句覆盖100%?

案例2-15:语句测试覆盖率。
假设令x=4、y=8、z=5。

  • 经过M1判断时,(4>3&&5<10)->(True&&True)->True,所以走b路径,执行语句S1。
  • 经过M2判断时,(4=4||8>5)->(True||True)->True,所以走d路径,执行语句S2。
  • 最后执行S3语句。

语句覆盖测试用例见表2-18。


299e4ea9fe819c5777e33dd70d91ed955bd3a868

由此可见,只需要设计一个测试用例,就可以达到语句覆盖率100%。

语句覆盖毕竟是最简单的覆盖,即使达到语句覆盖100%,软件也会出现问题。

这里举一个不能再简单的例子,看下面的被测试代码。

int foo(int a, int b) 
{ 
return a / b; 
}

如果软件测试工程师编写如下软件测试用例。

测试用例:a = 10、b = 5。

软件测试工程师的测试结果会告诉你,代码覆盖率达到了100%,并且所有软件测试用例都通过了。然而,遗憾的是,语句覆盖率达到所谓的100%,但是却没有发现最简单的Bug。比如,当b=0时,会抛出一个除以零的异常。

简而言之,语句覆盖就是设计若干个测试用例,运行被测程序,使得每一个可执行语句至少执行一次。这里的“若干个”意味着使用测试用例越少越好。

2.6.2 分支覆盖测试
分支覆盖又称判定覆盖,就是设计若干个测试用例,运行被测程序,使得程序中每个判定的取真分支和取假分支至少一次。

分支覆盖率的公式可以表示如下:

分支覆盖=被执行的分支数量/所有分支数量×100%

下面来看各种情况下的分支覆盖。

分支覆盖没有else的判断语句:既要执行if语句为True的情况,也要执行if语句为False的情况。

int f (int a){
int b=0;
if (a>0){
   b=1;
 }
return b;
}

分支覆盖率100%测试用例:f(1)、f(0),这是区别分支覆盖与语句覆盖需要特别注意的地方。

有else的判断语句:既要执行if语句,也要执行else中的语句。

int f (int a){
int b=0;
  if (a>0){
    b=1;
  } else{
    b=2;
    }
return b;
}

分支覆盖率100%测试用例:f(1)、f(0)。

在循环语句中:循环体内的语句必须有且有一次被运行。

int f (int a){
for (i=0;i<a;i++)
     printf(“hello”,s);
}

分支覆盖率100%测试用例:f(1)。

在多条件语句中:每个分支语句必须执行一次,另外还要涉及一种所有case没有覆盖到的情形。

int f (int a){
       switch (a) {
       case:1 { f1(); break;}
       case:2 { f2(); break;}
       case:3 { f3(); break;}
       case:4 { f4(); break;}
}

分支覆盖率100%测试用例:f(1)、f(2)、f(3)、f(4)、f(5) 5个。

下面来看在开始例子中,设计哪些数据可以达到分支覆盖的100%?

案例2-16:分支测试覆盖率。
令x=4、y=8、z=5。

  • 经过M1判断时,(4>3&&5<10)-> (True&&True) ->True,所以走b路径,执行语句S1。
  • 经过M2判断时,(4=4||8>5)-> (True||True) ->True,所以走d路径,执行语句S2。
  • 最后执行S3语句。这时测试到M1、M2分别为True的情形。

  然后令x=2、y=5、z=11。

  • 经过M1判断时,(2>3&&11<10)-> (False&&False) ->False,所以走c路径。
  • 经过M2判断时,(2=4||5>5)-> (False||False) ->False,所以走e路径。
  • 最后执行语句S3。这时测试到M1、M2分别为False的情形。

通过这两组数据,就可以达到该程序分支覆盖率测试100%,见表2-19。


453f65db8eeaa89e3d832443bb1d6ac2adb1c420

也可以设计另一组测试用例来达到分支覆盖的100%,这里不详细描述,见表2-20。

4d0981ab4d0dfd683d47a9d8141e916c30d34455

分支覆盖的优缺点如下。
  • 优点:分支覆盖具有比语句覆盖更强的软件测试能力,而且具有和语句覆盖一样的简单性,无需细分每个判定,就可以得到测试用例。
  • 缺点:一般情况下,大部分判定语句由多个逻辑条件组合而成(如判定语句中包含AND、OR、CASE),若仅判断其整个最终结果,而忽略每个条件的取值情况,必然会遗漏部分软件测试路径。

如本例中:x=4 || y>5,y>5写成y<5,即使判定覆盖测试用例达到100%,但是软件还是测试不出。

2.6.3 条件覆盖测试
在软件设计过程中,一个判定往往由多个条件组成,判定覆盖仅考虑了判定的结果,而没有考虑每个条件的可能结果。

条件覆盖是指选择足够的测试用例,使得运行这些测试用例时,判定中的每个条件的所有可能结果至少出现一次。

条件覆盖率的公式可以表示如下:

条件覆盖率=被执行的条件数量/所有条件数量×100%。

下面来看条件覆盖的例子:

int f (int a, int b){
int c=0;
if ((a>0) &&(b>0)){
   c=1;
}else{
   c=2
}return c;
}

表2-21为条件覆盖测试用例。


a30586baba45034100c2e1e8d7f7cde173d0cdb2

有些时候条件覆盖是达不到100%的,请看下面的程序:
int f (int a){
int c=0;
if ((a>0) &&(a<5)){
   c=1;
}else{
   c=2
}return c;
}


3b896c60bd0d494271318ba6525ceeb6834db041

由表2-22可以看到,既要达到a≤10又要达到a≥5是不可能的。

下面再来看在开始例子中,设计哪些数据可以达到条件覆盖的100%?

案例2-17:条件测试覆盖率。
令x=4、y=2、z=11。

  • 经过M1判断时,(4>3&&11<10)-> (True&&False) ->False,所以走c路径。
  • 经过M2判断时,(4=4||2>5)-> (True||False) ->True,所以走d路径,执行语句S2。
  • 最后执行S3语句。这时测试到条件判断分别为T1、F2、T3、F4。

令x=2、y=6、z=6。

  • 经过M1判断时,(2>3&&6<10)-> (False&&True) ->False,所以走c路径。
  • 经过M2判断时,(2=4||6>5)-> (False||True) ->True,所以走d路径,执行语句S2。
  • 最后执行S3语句。这时测试到的条件判断分别为F1、T2、F3、T4。

经过以上测试用例,T1、T2、T3、T4、F1、F2、F3、F4都被执行了一次,条件覆盖率达到100%,如表2-23所示。


82f506dfbcc50416ecf723d222f16e40b2877125

可以看出,这里虽然条件覆盖达到100%,但是语句覆盖都没有达到100%,S1语句根本没有执行到。

于是,在日常工作中为了弥补分支覆盖的不足,结合条件覆盖的不充分,提出了判定/条件覆盖。

2.6.4 判定/条件覆盖测试
判定/条件覆盖:设计足够的测试用例,使得判断中每个条件的所有可能取值至少执行一次,同时每个判断的所有可能判断结果,即要求各个判断的所有可能的条件取值组合至少执行一次。

我们仍旧以开始的程序为例。

案例2-18:判定/条件测试覆盖率。
令x=4、y=8、z=5。

  • 经过M1判断时,(4>3&&5<10)-> (True&&True) ->True,所以走b路径,执行语句S1。
  • 经过M2判断时,(4=4||8>5)-> (True||True) ->True,所以走d路径,执行语句S2。
  • 最后执行S3语句。这时测试到M1、M2分别为True的情形。条件判断分别为T1、T2、T3、T4。

令x=2、y=5、z=11。

  • 经过M1判断时,(2>3&&11<10)-> (False&&False) ->False,所以走c路径。
  • 经过M2判断时,(2=4||5>5)-> (False||False) ->False,所以走e路径。
  • 最后执行语句S3。这时测试到M1、M2分别为False的情形。条件判断分别为F1、F2、F3、F4。

可以看到:

  • 原子条件True,False都达到了:T1、T2、T3、T4、F1、F2、F3、F4。
  • 两个判断True,False也达到了:M1=True、False;M2=True、False。

所以,这样既达到了分支覆盖率是100%的情形,也达到了条件覆盖率是100%的情形,见表2-24。


ba196a14cbb2bbdaede40b75d603d27b4df4de4d

2.6.5 MC/DC(修订的条件/分支软件测试)覆盖测试
MC/DC(修订的条件/分支软件测试)准则是一种实用的软件结构软件测试率软件测试准则,已被广泛应用于软件验证和软件测试过程中。

案例2-19:MC/DC覆盖测试。

condition和decision的概念:

if (A || B && C ) {
        语句1;
}
Else{
     语句2;
}

A,B,C都是一个条件,而(A || B && C)叫一个Decision,如果是条件软件测试,只需两个CASE,就能软件测试,就是让这个decision为True和False各一次,就能达到。即:

  • A=True、B=False、C=True。
  • A=False、B=True、C=False。

如果是MC/DC,就得4个测试用例,怎么计算呢?

MC/DC覆盖测试在每个判定中的每个条件都曾独立影响判定的结果至少一次(独立影响意思是在其他条件不变的情况下,改变一个条件):

A || B && C
总结:每个条件对结果都独立起作用。

(1)如果A对结果起作用的话,B必须为False、C必须为True,这样结果就独立受A的值影响。(A||0&&1)->(A||0),(A、B、C取值分别为A=True、B=False、C=True和A=False、B=False、C=True)。

(2)同理,如果B对结果独立起作用,A必须为False、C必须为True,两种情况B为True、False各一个 (0||B&&1) (A、B、C取值分别为A=False、B=True、C=True和A=False、B=False、C=True)。

(3)如果C独立对结果起作用,就是让(A || B) 为True,为了减少用例,上面的用例已经含有这样的用例了,就取A为False、B为True,这样C独立起作用的用例为 (0||1&&C)->(1&&C)。(A、B、C取值分别为A=False、B=True、C=True和A=False、B=True、C=False)。

可以看出,每个条件各走了一次True和False,这样3个变量条件就会有6个用例, 但是其中里面有两个是重复的。

在1、2情形中均出现A=False、B=False、C=True。
在2、3情形中均出现A=False、B=True、C=True。
因此,最后的测试用例为。

  • A=True、B=False、C=True。
  • A=False、B=False、C=True。
  • A=False、B=True、C=True。
  • A= False、B=True、C=False。

需要进一步补充说明的是,MC/DC测试的主要目的是为了防止在组合条件表达式中包含副作用(side effect),见以下语句:

if (a() || b() || c()){ ... }

当b函数或c函数产生副作用时,MC/DC软件测试存在非常大的必要性。

原则上不应在组合条件表达式中调用产生副作用的函数。

2.6.6 路径覆盖测试
路径覆盖的含义是:选取足够多的软件测试数据,使程序的每条可能路径都至少执行一次(如果程序图中有环,则要求每个环至少经过一次)。

路径覆盖率的公式可以表示如下:

路径覆盖率=被执行的路径数量/所有路径数量×100%

案例2-20:路径覆盖(图2-16 )测试。


c32a73c9a5538e3e63db18c9f1b8686cd2bee85b

这里存在4条路径,分别为(1,3)、(1,4)、(2,3)、(2,4)。为了达到这些路径,设计测试用例见表2-25。

293b0f4c78c30ccd8de0899095334aef40a02ea9

回看本节开始的例子,设计什么数据可以使路径覆盖达到100%呢?第2.6.2节提到的两组测试用例,第一组测试用例分别执行了路径L4(abd)和L3(acd),第二组测试用例分别执行了路径L2(abe)和L1(ace)。所以,使用这4个测试用例,就可以达到路径覆盖测试100%。

路径覆盖测试用例见表2-26。


7bb09e27fef01ba66596d45dab0373beba4f91c7

以上6种覆盖率强弱关系如图2-17所示。

6c973def1a65bc24ce4f6247b0fa88cdf87fa29c

2.6.7 控制流测试
控制流测试经常用在嵌入式软件系统。

案例2-21:控制流测试。
如图2-18所示。


2c2e972f3ecf121da9d9f9824555913081bcddfd

首先:
  • 对经过A点的线进行排序:{1,2}、{1,3}、{1,4}、{6,2}、{6,3}、{6,4}。
  • 对经过B点的线进行排序:{2,6}、{3,6}、{4,6}、{2,5}、{3,5}、{4,5}。

然后进行总体排序

{1,2}、{1,3}、{1,4}、{2,5}、{2,6}、{3,5}、{3,6}、{4,5}、{4,6}、{6,2}、{6,3}、{6,4}。

 最后依次进行如下操作:

从1开始,5结束的连续序列,一直到把所有序列都输出完毕,见表2-27。


cdc351a8623516a4e423bbcfc74693e9e8b3211e

最后得到5个测试用例。

(1){1,2,5}。

(2){1,3,5}。

(3){1,4,5}。

(4){1,2,6,2,5}。

(5){1,3,6,4,6,3,5}。

2.6.8 单元测试中的基于代码的功能测试
在工作中,使用某些工具,可以通过图形化界面来了解各种测试的覆盖率。并且在单元测试中我们除了关心覆盖率的测试,还可以关心函数自身的功能测试。

案例2-22:单元测试中的基于代码的功能测试。
设计了函数float myAve(int32 a,int32 b),需求是获得a和b的平均数,如果输入参数有异常,则返回0.01。

可以设计这样一系列测试用例。

testMyAve (4, myAve(5,3)); //其中myAve(5,3)为要测试的函数,称为被测函数(SUT),4为期望结果,如果实际结果与期望结果相同,测试通过,否则测试不通过。
testMyAve (4.5, myAve(6,3))。
testMyAve (0, myAve(-1,+1))。
testMyAve (-4, myAve(-5,-3))。 
testMyAve (-4.5, myAve(-6,-3))。
testMyAve (1.5, myAve(6,-3))。
testMyAve (-1.5, myAve(-6,3))。
testMyAve (32767, myAve(32767, 32767))。
testMyAve (-32767, myAve(-32767,-32767))。
testMyAve (16383.5, myAve(32767, 0))。
testMyAve (32767, myAve(0, 32767))。
testMyAve (-32767, myAve(-32767,0))。
testMyAve (0, myAve(-32767, 32767))。
testMyAve (0.01, myAve(-32768, 32767))。
testMyAve (0.01, myAve(-32767, 32768))。
testMyAve (0.01, myAve(32767,-32768))。
testMyAve (0.01, myAve(32768,-32767))。
testMyAve (0.01, myAve(-32768,-32768))。
testMyAve (0.01, myAve(32768, 32768))。
这样再去查看,测试工具告诉我们各种测试覆盖率是否达到100%。本书第二篇第8.1节“单元测试工具Junit4测试工具”中会介绍Junit 4测试工具。

2.6.9 总结
白盒测试除了上述介绍的动态白盒测试外,还包括静态白盒测试,即代码审核。在静态审核中,代码书写规则非常重要,业界比较流行的编码规则请参看本篇附录C。

最后要指出白盒测试不仅在单元测试时进行,也可以在系统测试时进行,最早在嵌入式软件测试中,通过插桩的技术,通过工具得知各种覆盖率达到百分之几。现在上海有家公司对于非嵌入式产品,如APP程序,在运行系统测试时可以通过监控器,看到当时程序正在执行哪条语句,并且告诉各种覆盖率达到百分之几。这种技术叫作精准软件测试,是现在比较先进的软件测试方法。本书第二篇第11.4节“精准测试工具-星云测试平台”将会详细介绍。

相关文章
|
29天前
|
机器学习/深度学习 人工智能 监控
提升软件质量的关键路径:高效测试策略与实践在软件开发的宇宙中,每一行代码都如同星辰般璀璨,而将这些星辰编织成星系的过程,则依赖于严谨而高效的测试策略。本文将引领读者探索软件测试的奥秘,揭示如何通过精心设计的测试方案,不仅提升软件的性能与稳定性,还能加速产品上市的步伐,最终实现质量与效率的双重飞跃。
在软件工程的浩瀚星海中,测试不仅是发现缺陷的放大镜,更是保障软件质量的坚固防线。本文旨在探讨一种高效且创新的软件测试策略框架,它融合了传统方法的精髓与现代技术的突破,旨在为软件开发团队提供一套系统化、可执行性强的测试指引。我们将从测试规划的起点出发,沿着测试设计、执行、反馈再到持续优化的轨迹,逐步展开论述。每一步都强调实用性与前瞻性相结合,确保测试活动能够紧跟软件开发的步伐,及时适应变化,有效应对各种挑战。
|
1天前
|
测试技术 开发者 Python
自动化测试之美:从零构建你的软件质量防线
【10月更文挑战第34天】在数字化时代的浪潮中,软件成为我们生活和工作不可或缺的一部分。然而,随着软件复杂性的增加,如何保证其质量和稳定性成为开发者面临的一大挑战。自动化测试,作为现代软件开发过程中的关键实践,不仅提高了测试效率,还确保了软件产品的质量。本文将深入浅出地介绍自动化测试的概念、重要性以及实施步骤,带领读者从零基础开始,一步步构建起属于自己的软件质量防线。通过具体实例,我们将探索如何有效地设计和执行自动化测试脚本,最终实现软件开发流程的优化和产品质量的提升。无论你是软件开发新手,还是希望提高项目质量的资深开发者,这篇文章都将为你提供宝贵的指导和启示。
|
15天前
|
敏捷开发 监控 jenkins
自动化测试之美:打造高效的软件质量保障体系
【10月更文挑战第20天】在软件开发的海洋中,自动化测试如同一艘精准的导航船,引领项目避开错误的礁石,驶向质量的彼岸。本文将扬帆起航,探索如何构建和实施一个高效的自动化测试体系,确保软件产品的稳定性和可靠性。我们将从测试策略的制定、工具的选择、脚本的编写,到持续集成的实施,一步步描绘出自动化测试的蓝图,让读者能够掌握这一技术的关键要素,并在自己的项目中加以应用。
25 5
|
1月前
|
测试技术
软件质量保护与测试(第2版)学习总结第十三章 集成测试
本文是《软件质量保护与测试》(第2版)第十三章的学习总结,介绍了集成测试的概念、主要任务、测试层次与原则,以及集成测试的不同策略,包括非渐增式集成和渐增式集成(自顶向下和自底向上),并通过图示详细解释了集成测试的过程。
52 1
软件质量保护与测试(第2版)学习总结第十三章 集成测试
|
1月前
|
测试技术
软件质量保护与测试(第2版)学习总结第十章 黑盒测试
本文是《软件质量保护与测试》(第2版)第十章的学习总结,介绍了黑盒测试的基本概念和方法,包括等价类划分、边界值分析和因果图法,并通过具体例子展示了如何设计测试用例来验证软件的功能性需求。
64 1
软件质量保护与测试(第2版)学习总结第十章 黑盒测试
|
1月前
|
人工智能 人机交互 数据库
软件质量保护与测试(第2版)学习总结第一章
本文是《软件质量保护与测试》(第2版)第一章的学习总结,概述了软件的特征、分类、软件工程的层次化技术、现代软件开发的变化,以及软件质量的概念和评价体系,包括黑盒、白盒和灰盒测试方法。
31 1
软件质量保护与测试(第2版)学习总结第一章
|
15天前
|
Java 测试技术 持续交付
探索自动化测试的奥秘:提升软件质量的关键
【10月更文挑战第20天】 在当今快速发展的软件行业中,自动化测试已成为确保产品质量和加速开发周期的重要工具。本文将深入探讨自动化测试的核心概念、实施策略及其对软件开发生命周期的影响,旨在为读者提供一种全面理解自动化测试的视角,并展示如何有效地将其应用于实际项目中以提高软件质量和效率。
16 2
|
1月前
|
测试技术
软件质量保护与测试(第2版)学习总结第十一章 白盒测试
本文是《软件质量保护与测试》(第2版)第十一章的学习总结,详细讲解了白盒测试中的控制流测试技术,包括语句覆盖、判断覆盖、条件覆盖、判定-条件覆盖和路径覆盖等方法,并通过具体代码示例展示了如何设计测试用例来验证程序中的不同执行路径。
51 2
|
1月前
|
安全 程序员 网络安全
Kali渗透测试:对软件的溢出漏洞进行测试
Kali渗透测试:对软件的溢出漏洞进行测试
|
27天前
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
50 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)

热门文章

最新文章