IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 【无标题】 -> 正文阅读

[开发测试]【无标题】

软件测试与验证

期中考试范围 软件缺陷 逻辑覆盖 控制流测试

全是简答题,英文试卷

二、代码单元测试

动态的代码测试:在开发环境中,通过运行被测代码,验证其是否满足期望目标,尽早发现与目标不一样的缺陷

面向代码的动态测试分为两类:代码单元测试、代码接口测试

单元测试和集成测试的区别:一个是规模,以测试执行速度的快慢来界定,不超过0.1s。另一个是独立性,单元测试不能有任何外部资源的依赖,用到了测试替身

测试替身(Test Double):替代真实代码中依赖于数据库、网络和文件系统的代码,只有形没有内容,是假的东西

单元:功能相对独立、规模较小的代码

按照软件测试技术发展规律,我们面向代码测试内容讲解分成两大部分:测试技术,测试生成

image-20211011211058502

1.逻辑覆盖准则

逻辑测试:以代码中逻辑表达式结构为对象的测试,以期发现代码逻辑结构缺陷

逻辑结构缺陷:写代码时所犯错误在逻辑表达式上的可视化体现;逻辑表达式写错了,程序行为不正确

逻辑表达式缺陷类型DNF:

image-20211011212107496

基于逻辑覆盖准则的测试(Logical Coverage Criteria):用于衡量代码中逻辑表达式被测试的充分程度

image-20211011211721355

下图中的蓝色箭头表示A包含B,意思是B能够发现的缺陷一定可以被A发现,满足上面就一定满足下面的意思,但是判定覆盖和条件覆盖比较特殊

image-20211011211619279

满足逻辑覆盖准则 ≠ 高质量测试

高质量测试是发现高质量缺陷的测试

语句覆盖Statement Coverage

用来衡量被测代码中的语句得到执行的程度,如果测试集合能够使得被测代码中的每条语句至少被执行一次,那么则说该测试集合满足了语句覆盖

语句覆盖度:

image-20211012194904585

语句覆盖测试案例:

语句覆盖是定义在源代码上的,所以看的是源代码

可以在测试集合中增加多个测试用例使语句覆盖度达到100%,如例3

在逻辑测试当中,语句覆盖是最低级的,因为它只是把每个语句走了一遍,并没有去测试什么逻辑,如果把 if 里面的 && 改成 || 语句覆盖无法揭示错误

image-20211012195848817

判定覆盖Decision Coverage

衡量代码中的判定得到执行的程度,如果测试集合能够使得被测代码中的每个判定至少被执行一次(指每个判定的所有可能结果都至少出现一次,例如 if((num1>1)&&(num2==0)) 的真假结果都得到执行,才认为该判定被执行),那么则说该测试集合满足了判定覆盖

条件:不含布尔算子(与或非)的逻辑表达式,例如关系表达式、布尔变量等

image-20211012200657987

判定:一个或者多个条件通过一个或多个布尔算子连接起来的逻辑表达式

image-20211012200724162

判定覆盖度:

image-20211012201037101

判定覆盖测试案例:

注意指每个判定的真和假结果都至少出现一次,才叫做执行了

image-20211012201201999

判定覆盖的缺点:主要看的是逻辑操作符用的对,逻辑操作符用的对不代表逻辑就对,不一定能发现条件缺陷,如果把 num > 1 写成了 num > -1,则不能揭示错误

注意短路操作符 && 和 ||,即当出现了false或true就不走了,MC/DC准则产生的原因,所以上个例子正确的结果表格应该是

条件覆盖 Condition Coverage

衡量代码中构成判定的各个条件得到执行的程度,如果测试集合能够使得被测代码中的每个条件至少被执行一次,那么则说该测试集合满足了条件覆盖

每个条件被执行一次的含义:每个条件的所有可能结果都至少出现一次

image-20211012224610789

条件覆盖度:

image-20211012224426746

条件覆盖测试用例:

image-20211012224643109

notice:满足判定不一定满足条件,满足条件不一定满足判定

判定-条件覆盖 Decision-Condition Coverage(仅了解)

衡量代码中每个判定以及构成判定的每个条件得到执行的程度,如果测试集合能够使得被测代码中的每个判定至少被执行一次并且构成判定的每个条件至少被执行一次,那么则说该测试集合满足了判定-条件覆盖。

image-20211012225809115

修正的判定-条件覆盖

Modified Condition/Decision Coverage,MC/DC

期望构成每个判定的每个条件能独立地影响整个判定的结果

方法:

  1. 使用D表示判定,ci表示D的第i个条件

  2. D(ci=true)表示将D中所有ci使用true替换之后的判定表达式

  3. D(ci=false)表示将D中所有ci使用false替换之后的判定表达式

  4. 逻辑表达式Dci= D(ci=true)⊕D(ci=false) 可以用于计算ci独立影响判定时,其它条件的测试输入值

    异或算法表示两边取值不一样,所以只有Dci = true才能证明独立影响

  5. 注意不是每一个算法都能找到MC/DC结果

一个简单的例子:

image-20211027102650518

分析:

  1. 第一个式子里面,c2的值没有变化,一直为真,随着c1从真变成假,结果也从真变为了假,说明c1对我们整个判定结果产生了影响

  2. 第二个式子里面,c1的值没有变,变的只是c2的值,c2的值变了结果也变了,c2也能够独立影响

下面是一个综合例子:

求D的mc/dc测试用例,就是把满足c1,c2,c3的测试用例结果并起来?

image-20211027110649345

对于上面这个判定,使得它可以独立影响表达式结果,那么它的输入应该有3个,真真,假真,真假

注意,我们要算的是其他人取什么值才不会影响结果,使得我可以独立影响整个结果

image-20211027111307929

image-20211027111330999

分别求出来之后,把三种情况的测试情况求并集

image-20211027111440314

image-20211027113010723

下面一个实际应用:

image-20211027114137088

image-20211027114226598

多条件覆盖 Multiple Condition Coverage

image-20211027114315989

不是对着覆盖度来去设计测试用例,而是对着功能设计,再来根据覆盖度去修改用例

2. 逻辑覆盖测试工具

两种工具:IntelliJ IDEA Code Coverage Runner/JaCoCo

IDEA Code Coverage Runner

image-20211027132049218

IDEA branch coverage的计算方法与Jacoco不一样,而且似乎有缺陷

获取jacoco覆盖报告的方法

注意,想要获取覆盖率结果,工程里必须写单测代码,否则不会有结果

image-20211027134401131

点击mvn test

就可以在target的site目录下生成一个 index.html文件,点开文件即可查看报告

image-20211027135426001

覆盖报告分析

image-20211027120906000

JaCoCo Coverage Counters

  • Instructions

  • Branches

    计算所有 if 和 switch 语句的分支覆盖率

    无覆盖:行中没有分支被执行(红色菱形)

    部分覆盖:只执行了行中的部分分支(黄色菱形)

    全覆盖:行中的所有分支都已执行(绿色菱形)

  • Cyclomatic Complexity 环复杂度

    二值节点的个数 超过10的代码不能通过

    在(线性)组合中,可以通过一种方法生成所有可能路径的最小路径数

  • Lines 语句覆盖 跟这个语句相关的二进制指令执行

    当至少一条分配给该行的指令已被执行时,该行被视为已执行

    无覆盖:该行中未执行任何指令(红色背景)

    部分覆盖:只执行了该行中的一部分指令(黄色背景)

    全覆盖:该行中的所有指令都已执行(绿色背景)

  • Methods 方法覆盖

  • Classes 类覆盖

IDEA branch coverage的计算方法与Jacoco不一样,而且似乎有缺陷

3. 启发式规则

好的单元测试:r原则,自动化的,independent,可重复的repeatable

BCDE原则

image-20211106135205068

Heuristic Rules

没有理论基础,只是根据工程实践经验总结出来的,类似于头脑风暴

告诉你在设计测试用例时,可以遵循一个什么样的思路

Right—BICEP

image-20211106135451723
  • Right

    找到happy path 就是满足下面所有条件的测试用例

image-20211106140612949
  • B:边界条件(最重要)

    缺陷隐藏在代码里,一般聚集在边界上,程序员在边界处经常出问题

    虚假或不一致的输入值,格式错误的数据、错误的电话号码,可能导致数字溢出的计算,空值或缺失值

    年龄的边界很好找,但不是所有的边界条件都那么好找,所以我们引入了correct规则寻找边界条件

    image-20211106141751219 image-20211106142721596 image-20211106142941842 image-20211106144000725 image-20211106144432512
  • I:逆关系

    用“逆行为”测试被测试代码

    在数据库中插入一条记录后,查询该记录

    已经使用的款项总数 = 款项总数 – 剩余的款项数

  • C:交叉关系检查被测功能是否满足要求

    使用不同数据之间的关系进行测试

    已经使用的款项总数 = 款项总数 – 剩余的款项数

    image-20211106155036118
  • E:验错 Forcing Error Condition

    java中长生命周期对象引用了短生命周期对象,而短生命周期对象用完之后没有及时释放,就是内存泄露

    image-20211106155324475
  • P:查看性能

    image-20211106160426470

单元测试第一目标是要找缺陷,覆盖是顺带要达到的目标

4. Junit 测试脚本

Junit5 Features

image-20211106162807281 image-20211106162824971

junit所有特性都通过allowcation(at notation?)这个功能来实现的,要记住每个at notation的含义是什么,每个功能对应哪个notation要记住,下面几个老师单独提了一下:

  • @displayname的作用,提高可读性

  • @disable 忽略执行

  • @test instance lifecycle ??

@test instance lifecycle 具体用法参考 TestPerClass 和 TestPerMethod 两个文件

测试类不是你的被测类,测试类是testlifecycle,被测类是meetcalendar

image-20211107121101205

junit实例化测试类(instance)的方法有两种生命周期模式:

一种是在每一个测试方法之前,都会实例化一个测试类(独立性,减少测试和测试之间的依赖关系)

一种是一个测试类就实例化一个测试类的实例

@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestPerClassDemo {
    private int count = 0;

    @Test
    void addCount1(){
        count++;
        System.out.println("addCount1:" + count);
    }

    @Test
    void addCount2(){
        count++;
        System.out.println("addCount2:" + count);
    }
}

要是两个程序代码一样,只是@TestInstance的参数不同(以上面的程序为例):

第一种 MeetCalendarTestPerMethod

addcount1冒号后面是几

addcount2冒号后面是几

都是1,因为每个测试方法之前都会实例化一个testmethod实例

第二种 MeetCalendarTestPerClass

addcount1 addcount2 顺序不确定 但count是在累加的

image-20211106163232974

配置junit5环境

junit需要java8以上的支持,确认java版本

在项目里新建test目录,并且标记为测试根目录

image-20211106182229152

右键一个方法,generate test

image-20211106181557690

窗口提示我们当前项目并没有junit的支持,点击fix,自动下载jar包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OcXR2mbh-1638840354199)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20211106181613200.png)]

已经有了测试方法,至此测试环境已经准备就绪

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q0fOunJv-1638840354199)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20211106181833615.png)]

配置maven测试环境

setting maven runner jre改为1.8

image-20211107003928154

project structure project sdk 也选1.8

image-20211107004011376

Lifecycle

meetherejava里面有一个test lifecycle的测试类,每一个@test就是一个测试方法

image-20211107121709138

例如,避免在每个方法之前都要实例化一个对象,我们可以用@beforeeach的方法进行初始化

@BeforeEach
void init() {
    meet = new MeetCalendar();
}

@Test
void AddAnReservation() {
    meet.addReservation("Sun1", "gymb1", "2020-09-20 18:00");
    List<UserReservation> reservations = meet.getReservations();
    ......
}

以上代码和以下原始代码是一致的

@Test
void AddAnReservation() {
    meet = new MeetCalendar();
    meet.addReservation("Sun1", "gymb1", "2020-09-20 18:00");
    List<UserReservation> reservations = meet.getReservations();
    .......
}

下面的代码运行结果应该是

before all test, before each test, the first test, after each test, before each test, the second test, after each test, after all test

public class TestLifeCycle {

    @BeforeAll
    public static void initAll(){
        System.out.println("Before all tests");
    }

    @BeforeEach
    void init(){
        System.out.println("Before each test");
    }

    @Test
    void testDemoMethod1(){
        System.out.println("The 1st test");
    }

    @Test
    void testDemoMethod2(){
        System.out.println("The 2nd test");
    }

    @AfterEach
    void tearDown(){
        System.out.println("After each test");
    }

    @AfterAll
   static void  tearAll(){
        System.out.println("After all tests");
    }
}

Assertions

assertAll():

分组不同的断言,所有断言是被执行,任何失败都会一起报告

assertEquals("Sun", inputReservation.getUserName());
assertEquals(Site.gymb1, inputReservation.getSite());
assertEquals("2019-10-28 18:00",
             inputReservation.getReservationDateTime().format(
                 DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));

MeetHereMaven 项目中 MeetCalendarTest 的 addAnReservation() 中的以上代码,可以用assertAll()改写为

assertAll(
    () -> assertEquals("Sun", inputReservation.getUserName()),
    () -> assertEquals(Site.gymb1, inputReservation.getSite()),
    () -> assertEquals("2020-9-20 18:00",
                       inputReservation.getReservationDateTime().format(
                           DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))));

assertThrows():

系统抛出期望的异常

注意两点,一点系统是否抛出了期望的异常类型,一点处理异常的行为是不是正确

MeetHereMaven 项目中 DateTimeConvertTest 中有异常处理的例子

第一个参数是抛出的异常类型,第二个参数是我们输入的拉姆达表达式

@Test
@DisplayName("转换无效格式的日期,系统抛出异常")
void convertInvalidDateString(){
    // 1. 测试系统是否抛出了期望的异常类型
    Throwable exception = assertThrows(RuntimeException.class,()->DateTimeConvert.convertStringToDateTime("2019-9-20 18:00"));
    // 2. 处理异常的行为是不是正确
    assertEquals("输入预约时间格式不正确: [2019-9-20 18:00], 输入时间格式为[yyyy-MM-ddHH:mm]",exception.getMessage());
}

Parameterized tests 参数化测试

@ParameterizedTest 与 @Test 相同的生命周期

这是Junit5中实现的数据驱动自动化测试技术,通俗的讲就是只写一个测试方法,可以跑不同的数据

将测试数据和测试行为进行了分离,测试数据源和数据脚本是分开的,数据不是写在代码里

使用不同的参数多次运行测试,一段代码可以执行很多测试数据

学参数化测试要学哪些东西至少三点,最重要的是测试数据源,一是为测试定义测试数据类型,二是参数转换,测试数据源如何处理变量类型,类型匹配,类型转化,三是自己的属性

(1)定义数据源

参数指的的测试方法里面的方法的参数,测试数据源是这一个集合,每一条叫一个测试数据argument

image-20211107132111823

(1).1 测试数据源(argument source 简称 AS)的基本使用原则:

AS规则1

每个@Parameterized测试方法可以使用多个测试数据源,但是至少需要有一个

@ParameterizedTest
@ValueSource(strings = {"software testing","Junit5","Have fun!"}) 
// valuesource用一维数组的方式来定义参数化测试的数据源
void lowerCase(String candidate) {
    assertTrue(StringUtils.isAllLowerCase(candidate));
}

@ParameterizedTest
void testMethodWithoutArgumentSource(int candidate) {
    assertEquals(9,candidate);
}
// 第二个没有数据源会报错,org.junit.platform.commons.PreconditionViolationException: Configuration error: You must configure at least one set of arguments for this @ParameterizedTest

下面代码给了两个数据源,用了junit5提供的两种定义数据源的方式(共七种),一种是一维数组@ValueSource,一种是使用方法来指定数据源@MethodSource,这个方法的名字叫range,但是必须返回一个string兼容类型

下面这个方法会运行8次,range是包含0,不包含20,但是从第15个往后跳,只有15 16 17 18 19,运行5次

@ParameterizedTest
@ValueSource(ints = {1,2,3})
@MethodSource("range")
void testMethodWithMultipleArgumentSource(int candidate) {
    assertNotEquals(9,candidate);
}

AS规则2

每个测试数据源必须为测试方法的所有参数提供测试数据。例如,测试方法若有2个参数,参数1不能使用测试数据源1,而参数2使用其他数据源,即参数2也必须使用测试数据源1

比如下面这个程序是不对的会报错

@ParameterizedTest
@ValueSource(ints = {1,2,3})
@MethodSource("range")
void testMethodWithMultipleArgumentSource(int candidate1,int candidate2) {
    assertNotEquals(9,candidate1);
    assertNotEquals(-1,candidate2);
}

(1).2 常用的定义数据源的七种方法:

详见junitDemo项目

@ValueSource 一维数组
@NullSource, @EmptySource, @NullAndEmptySource  测试Null and Empty Sources:
@EnumSource 枚举数据源类型
@MethodSource
@CsvSource 逗号分割数据源,用的最多,excel可以生成csv,也有公司放在数据库里
@CsvFileSource
@ArgumentsSource
  • @EnumSource

    有两个可选的属性,用哪一个枚举量,跟模式是相关的,INCLUDE, EXCLUDE, MATCH_ALL,MATCH_ANY

    //1 must attribute
    value:  @EnumSource(TimeUnit.class)
    
    //2 Optional attributes
    name: @EnumSource(value = TimeUnit.class, names = { "DAYS", "HOURS" })
    mode: @EnumSource(value = TimeUnit.class, mode = EXCLUDE, names = { "DAYS", "HOURS" })
    
  • @CsvSource

    @ParameterizedTest
    @CsvSource({"apple,1","orange,2","'lemon,lime',0xF1"})
    void testWithCsvSource(String fruit,int rank) {
        assertNotNull(fruit);
        assertNotEquals(0, rank);
    }
    
    @ParameterizedTest
    @CsvSource(delimiter= ';',value = {"apple;1","orange;2","'lemon,lime';0xF1"})
    void testWithCsvSourcebyAtt(String fruit,int rank) {
        assertNotNull(fruit);
        assertNotEquals(0, rank);
    }
    
  • @MethodSource

    参考一种或多种方法(工厂方法)为测试方法提供测试数据

    这个制造数据的方法必须是static,不能带参数

    如果@MethodSource 中没有给出工厂方法,则选择与测试同名的方法作为工厂方法

    //字符串
    @ParameterizedTest
    @MethodSource({"stringArguments","stringArgumentsWithStream","stringArray"})
    void testWithString(String argument) {
        assertNotEquals("hysun", argument);
    }
    static List<String> stringArguments(){
        return Arrays.asList("software","testing");
    }
    static Stream<String> stringArgumentsWithStream(){
        return Stream.of("Junit","Mockito");
    }
    static String[] stringArray(){
        String[] str_data = {"selenium","appnium"};
        return str_data;
    }
    
    //单个数字
    @ParameterizedTest
    @MethodSource("singleInteger")
    void testSingleGrade(int grade){
        assertTrue(grade >= 0 && grade <= 100);
    }
    static int singleInteger(){
        return 85;
    }
    
    //list
    //测试方法有多个参数,工厂方法返回 Stream、Iterable、Iterator 或 Arguments 类型的数组
    @ParameterizedTest
    @MethodSource("provideWithList")
    void testMultipleGrade(int grade1,int grade2){
        assertTrue(grade1 >= 0 && grade1 <= 100);
        assertTrue(grade2 >= 0 && grade2 <= 100);
    }
    static List<Arguments> provideWithList(){
        return Arrays.asList(Arguments.of(90,45),
                             Arguments.of(60,30),
                             Arguments.of(85,42));
    }
    

    工厂方法可以是测试类中的方法,也可以是其他类的方法
    至于来自外部类的工厂方法,需要完整的类名,不要忘记包名!!

    image-20211108151555338

  • @CsvFileSource

    通过引用resource里面的文件

    image-20211108181343843

    image-20211108181319904

    如果把lemon,line的双引号改成了单引号

    image-20211108181423322

    则下面的代码会报错

    image-20211108181501515

    如果想要提取excel文件并跳过表头,numLinesToSkip = 1

    image-20211108181707592

  • @ArgumentsSource

    通过实现 ArgumentProvider 接口自定义参数源

    image-20211108182129247

    下面定义一个类实现接口

    public class GradeArgumentsProvider implements ArgumentsProvider {
    
         @Override
         public Stream<? extends Arguments>  provideArguments(ExtensionContext var1) {
    
            return IntStream.of(90,60,85)
                    .mapToObj(
                              grade->
                                      Arguments.of(grade,0.5*grade)
                    );
         }
    }
    

    然后可以在另一个类里使用 ,ArgumentsSource参数是实现了接口的类

    @ParameterizedTest
    @ArgumentsSource(GradeArgumentsProvider.class )
    
    void testFinalGrateGradeWithArgumentProvider(int grade, double finalGrade){
        assertEquals(2.0, grade/finalGrade,0.0001);
    }
    

(2)参数类型转换

显示转换

实现 ArgumentConverter 接口/扩展 SimpleArgumentConverter

SimpleArgumentCoverter 是一个抽象类实现了 ArgumentCoverter接口

image-20211108191400733

我们可以直接定义一个类继承 SimpleArgumentCoverter

image-20211108191630836

在参数中@ConvertWith

image-20211108191905574

隐式转换

Junit5 内置隐式类型转换器:字符串转换为参数类型

image-20211108190841210

回退字符串到对象的转换Fallback String-to-Object Conversion:工厂方法和工厂构造函数

image-20211108192106155

(3)给测试命名

@ParameterizedTest(name=“[{index}] {arguments}”)

每一次测试的名字,提高可读性

index第几次执行,后面argument是把所有参数值都列出来

举例1

image-20211108192616737

举例2

image-20211108192447697

生命周期方法不可以参数化,但可以在生命周期测试方法中去获取信息,提高可读性:用到两个类TestInfo和TestReporter

image-20211108192915626

5. mockito

meetheremaven中有一个类叫 add

基于行为的测试,不是基于状态的测试

基于行为需要mokito这样一个框架帮助我们,doc verify

设计脚本的三个阶段arrange action assert

6. 基于控制流的测试

recording4 7:14 开始的

前面用了单元测试主要用的技术和方法,现在要学测试用例自动生成方法

测试理论的三大支柱:基于控制流的(Control Based Tests Generation),基于数据流的(Data Flow Based Testing),基于遍历的(Mutation Testing)

基于控制流主要介绍基路径测试:基于程序控制结构设计可覆盖基本执行路径的测试的测试设计技术

  1. 构建控制流图(CFG)
  2. 计算基路径集,两个算法复杂度都不低
  3. 推出/计算测试用例

6.1 构建控制流图

控制流图是对代码中所有执行的一个抽象,用一张图表达出来

两个元素,一个是节点,一个是边,符合离散数学中图论的定义

节点是指代语句或一系列顺序执行的语句,如果第一个语句被执行,所有语句都将被执行

指代代码当中控制的转移,是对指令顺序的一个抽象

if语句

image-20211108200656054

switch语句:分支可以有好多个

image-20211108200748766

覆盖度工具中有个环复杂度,计算的是二值节点,switch就不是二值节点

while语句和do-while语句

image-20211108201008860

for语句

image-20211108201108544

一个例子,注意红色箭头容易出错的部分

image-20211108201330748

学会如何去切代码!

image-20211108202044427

切代码exercise:

image-20211108202118557 image-20211108202131133

6.2 计算基路径

基于控制流测试的第二步:计算基路径

求出基路径:找到被测代码中必须要执行的测试路径

路径:首尾相连的边构成的节点序列

路径的长度:路径中包含的边的数量,允许长度为0的路径就是一个节点,一条语句就是一个节点

子路径:节点子序列构成的路径

根据控制流图,可以得到相应的路径,从长度为1到长度为10的路径都有,这里的路径不是程序的完整路径,只是节点的序列

而基路径是要在成千上万的路径中找出比较有代表性的路径集合,因为资源有限不可能每一条路径都去测试

image-20211108161719278

complete path完整路径:这条路径的开始必须是开始节点,终止必须是终止节点

Infeasible Complete Path不可达路径:水浒传第134位?

simple path简单路径:是一种特殊的路径,除了第一个节点和最后一个节点外,中间节点出现的次数有且只有一次。(目的是剔除中间包含循环的那些路径)

image-20211108220227897

怎样去处理这么庞大数量的路径呢,基路径帮助我们减少要去测试的路径

prime path基路径

不作为任何其他简单路径的正确子路径的简单路径,基路径不一定是一条完整路径

所以上一道题只有长度为3的简单路径是基路径

image-20211108220439743

控制流图的所有路径都可以通过基路径的加或者乘得出,跟向量中的"基"含义一样

How to calculate prime path

  1. Exhaust method (穷举)
  2. Node tree method (节点树法,同学想出来的)

学期作业可以构造复杂度更低的方法来完成

(1)暴力法step

  1. 从len 0 开始列出所有的简单路径
  2. 将列出来的不能再扩展的路径标记感叹号
  3. 继续扩展列出 len 1 len 2 … len 4,直到所有的集合都被标记上感叹号
  4. 长度最长的一定是基路径
  5. 再找出其他长度(从高到低找)里不是别人子路径的简单路径
image-20211108222240027 image-20211108222629989

(2)节点树法 step

方法介绍:

  • 节点树

    以G中的节点为根节点建立的树,且满足树中除根节点和叶节点 可以相同外,从根节点到每个树中节点的路径中,每个节点的出现次数有且仅有 1 次。在节点树中,每条从根节点到叶节点的路径即为一条简单路径

  • 简单节点树

    若节点树T不是任何其它节点树的子树,则称节点树T为简单节点树

    所有简单节点树的从根节点到叶节点的路径集合为备选的基路径 集合

步骤

  1. 画出每个结点的节点树
  2. 0节点数都是基路径,再一个一个找没有被0节点数的路径包含的基路径
image-20211108223653348

6.3 自动生成测试集合

“ Deriving Test Cases ”

测试生成算法目标:Prime Path Coverage (PPC) 每条基路径应至少被一个测试用例执行一次

步骤:

  1. 把基路径扩展成完整路径:从最长的基路径开始,将其扩展成包含CFG的初始节点和终止节点的完全路径
  2. 计算使得路径能够被执行的输入作为测试输入

方法:

  1. 观察法

  2. 约束求解法:将路径构造为约束表达式,再用工具求解

    当构成路径表达式的各个变量的取值使得路径表达式的结果为真,说明在该取值下,程序执行该条路径

    我们这个课约束求解器用的是Z3

生成工具:把代码通过soot编译成中间形式,利用soot提供的控制流图工具构造被测源码的控制流图,找基路径soot里面有个get什么什么方法,这里没有写基路径,这是交给大家学期作业去写的,测下来对循环不大友好会出错

demo

假设根据控制流算出了两条路径,接下来就要去找约束表达式:

不再用 1→2 表示路径,而是用 op1>=op2 来表示这条路径

image-20211122233124185

7.基于数据流的测试

控制流考虑的是代码中的分支机构,数据流考虑对变量进行定义和使用的测试

本章包含的问题:如何构造数据流图、怎样基于数据流图找数据输入、哪些数据流覆盖准则

数据流不是测试当中特有的概念,是编译原理里面的

跟数据流相关的概念:

  • 变量的定义def:将变量的值存入内存的语句,对变量的写操作 x=44 input

  • 变量的使用use:读取或访问变量的值的语句,不改变变量的值,比如条件语句

  • 数据流测试的关键就是,检测变量的定义有没有用,是不是该用,是不是正确

  • 有些语句既读又写

    image-20211124220014128

  • 区别c-use和p-use

    image-20211124220104978

exercise 1

注意6不是p的定义节点

程序缺陷在于没有回收内存空间

image-20211204202823857

exercise 2

image-20211206200239003

数据流图

image-20211206203302054

控制流测试设计的思想:执行程序路径到达期望的控制覆盖准则

数据流测试设计的思想:执行程序路径到达期望的数据流覆盖准则

du pair 定义使用对:一个二元组 (li,lj),在li处定义,在lj处使用

def clear定义清除路径:从li开始,在lg结束,如果变量是定义清除的,那么除了 li 以外其他的节点都是不是定义节点

??du path 定义使用路径:首先是简单路径,必须是定义清除的

定义使用路径的两种表示方式,第二个集合应该等于第一个集合的并集

image-20211206214827206

例题

image-20211206214226764

数据流覆盖准则

全定义覆盖 ADC:对每个变量v而言,每个定义必须被至少执行一次

全使用覆盖 AUC:对每个变量而言,所有的使用必须在测试用例中出现一次

全定义使用路径覆盖 ADUPC:对于每个变量而言,执行所有的定义使用路径

image-20211207001103498

exercise:

第一步画出控制流图

image-20211207012429900

第二步画出数据流图

image-20211207012413466

第三步

列出定义使用对

以2为开头的

image-20211207022317256

以10开头的,注意从10到10也是一个路径

image-20211207022348973

第四步

选出全定义覆盖

image-20211207022829917

第五步

选出全使用覆盖路径

注意绿色的部分挑一个出来就像

image-20211207022805511

第六步

选出全定义使用覆盖路径

image-20211207022906062

8. 变异测试

基本概念

企业界的理解就是做出来就行

学理届一定要系统的用科学的方法和态度把它做出来

变异测试是揭错能力最强的方法,在代码当中故意植入一些缺陷,但是在工程界不被广泛应用

他开始是用来评估测试揭错能力的标准,后来才演变成了测试生成方法

变异算子

缺陷,用于引入错误的方法

对被测代码做语法上的改变,这种改变的途径就是变异算子,一般是一个集合,每个变异算子代表了一类缺陷

每用一个变异算子,就生成一个变异体mutant,一次只改变一个地方(可以是变量交换,可以是改变符号)

一阶变异:Only one change

高阶变异:More than one changes

image-20211207030015050

变异得分

客观的数量指标

计算方法:被杀死的变异体 / (被杀死的变异体+存活的变异体)

分母剔除了等价变异体,就是运行结果跟以前完全一样的

NE表示只要前面有一个不一样,后面就不用算了

image-20211207031541309

基于变异的测试生成

rip模型

可达性:测试导致错误语句被到达(在变异中——变异语句)

感染:测试导致错误的语句导致错误的状态

传播:不正确的状态传播到不正确的输出

RIP 模型导致突变覆盖的两种变体(强杀和弱杀)

Mutation Coverage (MC变异覆盖) :杀死所有的变异体,运行出来结果全都不一样,要满足rip模型

基于强变异覆盖

强杀:生成用例是通过输出结果来判断变异体是不是被杀死,有可观测的结果,要求非常高

image-20211207033617742

基于弱变异覆盖

弱杀:只用满足可达性和感染性就行了, 不需要满足传播性了,条件放宽了

image-20211207033902270

等价变异体

也可以通过约束求解表达式来分析

源代码的等价,然而前面的语句是“minVal = A” 替换,我们得到:“(B < A) != (B < A)”,因此没有输入可以杀死这个突变体

image-20211207034131505

exercise

image-20211207034245067

image-20211207034302213

变异算子设计

程序每一句话都可以构造出一个变异算子,问题是构造这个变异算子有没有价值

如果专门为杀死由一组变异算子 O = {o1, o2, …} 创建的突变体而创建的测试也以非常高的概率杀死由所有剩余变异算子创建的突变体,则 O 定义了一组有效的变异算子

插入一元运算符和修改一元和二元运算符都有效

等价变异体的判定问题

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-12-08 14:06:54  更:2021-12-08 14:07:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/18 6:14:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码