一文弄懂JUnit5相关注解

news2024/11/24 8:58:18

JUnit5

JUnit是Java生态系统中最流行的单元测试框架之一。JUnit5版本包含许多令人兴奋的创新,其目标是支持Java8和更高版本中的新功能,并支持多种不同风格的测试。

Maven依赖

启动JUnit5.x.0非常简单;我们只需要将以下依赖项添加到pom.xml中:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.8.1</version>
    <scope>test</scope>
</dependency>

此外,集成开发工具,如Eclipse、IntelliJ 支持直接运行JUnit单元测试。新版本IntelliJ默认支持JUnit5。当然,开发者也可以使用Maven Test目标运行测试。

JUnit5 架构

JUnit5由三个不同子项目的不同模块组成, JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

JUnit Platform

  • JUnit Platform 负责在JVM上启动测试框架。它在JUnit及其客户端(如构建工具)之间定义了一个稳定而强大的接口。
  • JUnit Platform 轻松地将客户端与JUnit集成,以发现和执行测试。
  • 定义了TestEngine API,用于开发在JUnit平台上运行的测试框架。通过实现自定义测试引擎,我们可以将第三方测试库直接插入JUnit。

JUnit Jupiter

本模块包括用于在JUnit 5中编写测试的新编程和扩展模型。与JUnit 4相比,新注释如下:

  • @TestFactory – 表示作为动态测试的测试工厂的方法
  • @DisplayName – 定义测试类或测试方法的自定义显示名称
  • @Nested – 表示带注释的类是嵌套的非静态测试类
  • @Tag – 过滤筛选测试标记
  • @ExtendWith – 注册自定义扩展
  • @BeforeEach – 表示将在每个测试方法之前执行带注释的方法(相当于之前的@before)
  • @AfterEach –表示将在每个测试方法之后执行带注释的方法(相当于之前的@after)
  • @BeforeAll – 表示注释的方法将在当前类中的所有测试方法之前执行(相当于之前的@BeforeClass)
  • @AfterAll – 表示注释方法将在当前类中的所有测试方法之后执行(相当于之前的@AfterClass)
  • @Disable – 禁用测试类或方法(相当于之前的@Ignore)

JUnit Vintage

JUnit Vintage支持在JUnit5平台上运行基于JUnit3和JUnit4的测试。

基础注解

@BeforeAll @BeforeEach

package com.andy.spring.boot.docker.junit5;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;


public class JunitTest {

    @BeforeAll
    public static void setUp(){
        System.out.println("只运行一次,在所有的测试方法执行前运行");
    }

    @BeforeEach
    public void init() {
        System.out.println("@BeforeEach - 在每个测试方法之前都会运行");
    }

    @Test
    public void test1() {
        System.out.println("test - 执行Test 1 测试方法");
    }

    @Test
    public void test2() {
        System.out.println("test - 执行Test 2 测试方法");
    }
}

如下图,执行在测试类上执行 Run JunitTest. 注意:@BeforeAll 注解方法必须为静态方法,使用static关键字修饰

在这里插入图片描述

@DisplayName @Disabled

package com.andy.spring.boot.docker.junit5;

import org.junit.jupiter.api.*;


public class JunitTest2 {

    @DisplayName("Single test successful")
    @Test
    void testSingleSuccessTest() {
        System.out.println("Success");
    }

    @Test
    @Disabled("Not implemented yet")
    void testShowSomething() {
        System.out.println("testShowSomething");
    }
}

如下图,执行在测试类上执行 Run JunitTest2, 使用 @Disabled 注解的测试方法被禁用并没有执行

在这里插入图片描述

@AfterEach @AfterAll

package com.andy.spring.boot.docker.junit5;

import org.junit.jupiter.api.*;


public class JunitTest3 {

    @AfterAll
    public static void setUp(){
        System.out.println("只运行一次,在所有的测试方法执行后运行");
    }

    @AfterEach
    public void init() {
        System.out.println("@BeforeEach - 在每个测试方法之后都会运行");
    }

    @Test
    public void test1() {
        System.out.println("test - 执行Test 1 测试方法");
    }

    @Test
    public void test2() {
        System.out.println("test - 执行Test 2 测试方法");
    }
}

这两个注解跟之前的@BeforeAll、@BeforeEach效果类似,只是执行顺序相反。注意:@BeforeAll 注解方法必须为静态方法,使用static关键字修饰

@ParameterizedTest

表示方法是参数化测试。除非重写这些方法,否则将继承这些方法。


import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.util.StringUtils;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class JunitTest8 {

    @ParameterizedTest
    @ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
    void palindromes(String candidate) {
        assertTrue(!StringUtils.isEmpty(candidate));
    }
}

如下图,将预定义的参数逐个传入测试方法执行

在这里插入图片描述

@RepeatedTest

@RepeatedTest(10)
    void repeatedTest() {
        System.out.println("hello world");
    }

如下执行结果,表示被测试方法可重复执行

在这里插入图片描述

@TestClassOrder

@Nested标注的嵌套试类中,使用@TestClassOrder指定不同类的执行顺序。这样的注释是继承的。

import org.junit.jupiter.api.ClassOrderer;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestClassOrder;

@TestClassOrder(ClassOrderer.OrderAnnotation.class)
class OrderedNestedTestClassesDemo {

    @Nested
    @Order(1)
    class PrimaryTests {

        @Test
        void test1() {
            System.out.println("test1");
        }
    }

    @Nested
    @Order(2)
    class SecondaryTests {

        @Test
        void test2() {
            System.out.println("test2");
        }
    }
}

@TestMethodOrder

真正的单元测试通常不应依赖于它们的执行顺序,但有时需要强制执行特定的测试方法执行顺序 — 例如,在编写集成测试或功能测试时,测试顺序很重要。

import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

@TestMethodOrder(OrderAnnotation.class)
class OrderedTestsDemo {

    @Test
    @Order(1)
    void nullValues() {
        System.out.println(" test 1");
    }

    @Test
    @Order(2)
    void emptyValues() {
        System.out.println(" test 2");
    }

    @Test
    @Order(3)
    void validValues() {
        System.out.println(" test 3");
    }

}

@TestInstance

在学习这个注解之前,我们先看以下的测试代码

class AdditionTest {

    private int sum = 1;

    @Test
    void addingTwoReturnsThree() {
        sum += 2;
        assertEquals(3, sum);
    }

    @Test
    void addingThreeReturnsFour() {
        sum += 3;
        assertEquals(4, sum);
    }
}

在测试类上按照顺序依次执行这两个测试方法,均测试通过。这是由于在默认情况下,每个测试方法执行之前,sum都会被初始化一次,赋值为1。那么有没有可能需要保留之前测试方法计算之后的值呢?

@TestInstance就是干这个用的,它有两个设置级别:

  • TestInstance.Lifecycle.PER_METHOD - 变量在测试方法之前重新初始化,默认值
  • TestInstance.Lifecycle.PER_CLASS - 变量的作用范围在每个测试类,即会保留之前测试方法计算后的值

当在测试类上新增 @TestInstance(TestInstance.Lifecycle.PER_CLASS) ,测试结果就不正常了(如下图,理由是保留之前的计算值)

在这里插入图片描述

@Tag

测试类、测试方法都可以增加 @Tag 注解标记,这些标记稍后可用于过滤测试发现和执行。

@Test
@Tag("IntegrationTest")
public void testAddEmployeeUsingSimpelJdbcInsert() {
}

@Test
@Tag("UnitTest")
public void givenNumberOfEmployeeWhenCountEmployeeThenCountMatch() {
}

假设定义以上两个测试方法,并打上不同的标记。后续可以使用标记过滤特定场景的测试要求,如下:

@SelectPackages("com.baeldung.tags")
@IncludeTags("UnitTest")
public class EmployeeDAOUnitTestSuite {
}

运行 com.baeldung.tags 包下标记为 UnitTest 的所有测试方法

@ExtendWith

开发者使用@ExtendWith注解扩展一个或多个扩展类。其目的是扩展测试类、测试方法的表现行为,方便模块化测试工作中的代码复用。

  • 定义扩展类

    import org.junit.jupiter.api.extension.AfterEachCallback;
    import org.junit.jupiter.api.extension.BeforeEachCallback;
    import org.junit.jupiter.api.extension.ExtensionContext;
    
    public class MyExtension implements BeforeEachCallback, AfterEachCallback {
    
        @Override
        public void beforeEach(ExtensionContext context) throws Exception {
            System.out.println("MyExtension.beforeEach()");
        }
    
        @Override
        public void afterEach(ExtensionContext context) throws Exception {
            System.out.println("MyExtension.afterEach()");
        }
    }
    
  • 扩展测试类

    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    
    @ExtendWith(MyExtension.class)
    public class JUnit5ExtensionTest {
        @Test
        void test1() {
            System.out.println("  test1()");
        }
    
        @Test
        void test2() {
            System.out.println("  test2()");
        }
    }
    

@RegisterExtension

开发者可以将此注释应用于测试类中的字段。这种方法的一个优点是,我们可以直接将扩展作为测试内容中的对象进行访问。JUnit将在适当的阶段调用扩展方法。例如,如果扩展实现BeforeEachCallback,JUnit将在执行测试方法之前调用其相应的接口方法。

  • 定义扩展

    
    import org.junit.jupiter.api.extension.BeforeAllCallback;
    import org.junit.jupiter.api.extension.BeforeEachCallback;
    import org.junit.jupiter.api.extension.ExtensionContext;
    
    public class LoggingExtension implements
            BeforeAllCallback, BeforeEachCallback {
    
        // logger, constructor etc
    
        @Override
        public void beforeAll(ExtensionContext extensionContext)
                throws Exception {
            System.out.println("beforeAll : " + extensionContext.getDisplayName());
        }
    
        @Override
        public void beforeEach(ExtensionContext extensionContext) throws Exception {
            System.out.println("beforeEach : " + extensionContext.getDisplayName());
        }
    
    }
    
  • 注册扩展

    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.RegisterExtension;
    
    public class RegisterExtensionTest {
    
        @RegisterExtension
        static LoggingExtension staticExtension = new LoggingExtension();
    
        @Test
        public void demoTest() {
            // assertions
        }
    }
    
  • 验证测试

    在这里插入图片描述

JUnit 断言

JUnit5在语法上使用Java8的一些新特性,尤其是lambda表达式。

Assertions

断言已移动到org.unit.jupiter.api。断言和已显著改进。如前所述,开发者可以在断言中使用lambdas:

public class JunitTest4 {

    @Test
    void lambdaExpressions() {
        List<Integer> numbers = Arrays.asList(1, 2, 3);
        assertTrue(numbers.stream().mapToInt(t -> t.intValue()).sum() > 5, () -> "Sum should be greater than 5");
    }
}

尽管上面的示例很简单,但对断言消息使用lambda表达式的一个优点是它的求值很慢,如果消息构造很昂贵,这可以节省时间和资源。

开发者还可以使用assertAll()对断言进行分组,这将使用MultipleFailuresError报告组内的任何失败断言:

@Test
    void groupAssertions() {
        int[] numbers = {0, 1, 2, 3, 4};
        assertAll("numbers",
                () -> assertEquals(numbers[0], 1),
                () -> assertEquals(numbers[3], 3),
                () -> assertEquals(numbers[4], 1)
        );
    }

执行结果如下:

在这里插入图片描述

Assumptions

假设仅在满足某些条件时用于运行测试。这通常用于测试正常运行所需外部依赖条件,但与所测试的内容没有直接关系。开发者可以使用assumeTrue()、assumeFalse()和assumeThat()声明一个假设:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.*;

public class JunitTest5 {

    @Test
    void trueAssumption() {
        assumeTrue(5 > 1);
        assertEquals(5 + 2, 7);
    }

    @Test
    void falseAssumption() {
        assumeFalse(5 < 1);
        assertEquals(5 + 2, 7);
    }

    @Test
    void assumptionThat() {
        String someString = "Just a string";
        assumingThat(
                someString.equals("Just a string"),
                () -> assertEquals(2 + 2, 4)
        );
    }
}

如果假设失败,则抛出TestAbortedException,并跳过测试。

JUnit5 高级特性

异常测试

JUnit 5中有两种异常测试方法,我们可以使用assertThrows()方法实现这两种方法:

package com.andy.spring.boot.docker.junit5;

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class JunitTest6 {

    @Test
    void shouldThrowException() {
        Throwable exception = assertThrows(UnsupportedOperationException.class, () -> {
            throw new UnsupportedOperationException("Not supported");
        });
        assertEquals("Not supported", exception.getMessage());
    }

    @Test
    void assertThrowsException() {
        String str = null;
        assertThrows(IllegalArgumentException.class, () -> {
            Integer.valueOf(str);
        });
    }
}

第一个示例验证抛出的异常的详细信息,第二个示例验证异常的类型。

测试组件

接下来学习一个JUnit5的新特性 Test Suites - 测试组件。将探讨在一个测试场景中聚合多个测试类的概念,以便我们可以一起运行这些测试类。JUnit5提供了两个注释@SelectPackages和@SelectClasses来创建测试组件。

@Suite
@SelectPackages("com.baeldung")
@ExcludePackages("com.baeldung.suites")
public class AllUnitTest {}

@SelectPackage用于指定运行测试组件时要选择的包的名称。在我们的示例中,它将运行所有测试。@ExcludePackages排除指定包下面的所有测试类。

@Suite
@SelectClasses({AssertionTest.class, AssumptionTest.class, ExceptionTest.class})
public class AllUnitClassTest {}

@SelectClasses注解用于指定运行测试套件时要选择的类。请注意,上述三个测试类可以不在同一个package下面。

Test Suites对于大规模的单元测试比较友好,开发/测试人员只需要编写测试用例,就可以大批量的运行测试代码,提高了开发的效率

动态测试

JUnit5的动态测试特性,它允许我们声明和运行运行时生成的测试用例。与静态测试(在编译时定义固定数量的测试用例)相反,动态测试允许我们在运行时动态定义测试用例。动态测试可以通过带有@TestFactory注释的工厂方法生成,请看一下代码:

package com.andy.spring.boot.docker.junit5;

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class JunitTest7 {

    private List<String> in = new ArrayList<>(Arrays.asList("Hello", "Yes", "No"));
    private List<String> out = new ArrayList<>(Arrays.asList("Cześć", "Tak", "Nie"));

    @TestFactory
    Stream<DynamicTest> translateDynamicTestsFromStream() {
        // 1. 循环list数组 每个值都进行动态测试 并赋予特定的显示名称
        return in.stream()
                .map(word -> DynamicTest.dynamicTest("Test translate " + word, () -> {
                    int id = in.indexOf(word);
                    assertEquals(out.get(id), translate(word));
                }));
    }

    private String translate(String word) {
        if ("Hello".equalsIgnoreCase(word)) {
            return "Cześć";
        } else if ("Yes".equalsIgnoreCase(word)) {
            return "Tak";
        } else if ("No".equalsIgnoreCase(word)) {
            return "Nie";
        }
        return "Error";
    }
}

这个例子非常简单,假设希望使用两个ArrayList来翻译单词,分别命名为in和out。工厂方法必须返回Stream、Collection、Iterable或Iterator。在我们的例子中,我们选择了一个Java8Stream。

请注意@TestFactory方法不能是私有的或静态的。测试的数量是动态的,它取决于ArrayList的大小。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/53570.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

昆石网络 VOS3000虚拟运营支撑系统任意文件读取漏洞

漏洞描述&#xff1a; 昆石网络 VOS3000虚拟运营支撑系统 通过 %c0%ae%c0%ae 等字符绕过检测&#xff0c;可导致任意文件读取漏洞。 漏洞利用条件: 对⽤户查看或下载的⽂件没有限制或者限制绕过&#xff0c;就可以查看或下载任意⽂件 漏洞影响范围&#xff1a; VOS3000 漏…

阿里云Redis性能压力测试(二十)

文章目录1.云Redis性能压力测试2.安装redis-banchmark压测工具3.压测两节点的Redis集群4.压测四节点的Redis集群4.1.扩容集群为四节点4.2.压力测试5.压测结果对比1.云Redis性能压力测试 我们当前Redis集群是2个节点2个分片&#xff0c;使用redis-benchmark工具对Redis集群进行…

轨迹预测——day 57 基于车道交叉和考虑驾驶方式的终点生成模型的前目标车辆轨迹预测

Trajectory Prediction of Preceding Target Vehicles Based on Lane Crossing and Final Points Generation Model Considering Driving Styles导读II.问题表述与系统架构A. Trajectory Prediction for PTVs&#xff08;preceding target vehicles&#xff09;B. Position and…

python自学程序练习01:99乘法表

#完成99乘法表 #1*11 #1*22 2*24 #1*33 2*36 3*39 #很明显要两个循环print(打印99乘法表&#xff1a;) for i in range(1,10):for j in range(1, i1):print(f{j}*{i}{j * i}, end )结果如上图所示&#xff0c;很明显发现&#xff0c;是我们想要的数据但是他的形式需要有所修改。…

Vue3创建项目(四)main.js配置,避坑指南

系列文章目录 第一篇 Vue3创建项目&#xff08;一&#xff09;新手教程 第二篇 Vue3创建项目&#xff08;二&#xff09;router路由配置和使用 第三篇 Vue3创建项目&#xff08;三&#xff09;Vuex配置 目录 系列文章目录 main.js配置&#xff0c;直接看图&#xff0c;如下…

作为前端你还不懂MutationObserver?那Out了

&#x1f431;个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️作者简介&#xff1a;前端领域新星创作者、华为云享专家、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab;系列专栏&#xff…

Netty(一)- Netty与BIO、NIO、AIO介绍

文章目录一、Netty的介绍二、Netty的应用场景1. 互联网行业2. 游戏行业3. 大数据领域三、I/O模型1. Java BIO&#xff08;1&#xff09;Java BIO 基本介绍&#xff08;2&#xff09;Java BIO 工作机制&#xff08;3&#xff09;Java BIO 应用实例&#xff08;4&#xff09;Java…

css如何快速将网站设置为灰色背景

突然想起写这篇文章是因为&#xff0c;公司的产品大早上打电话说&#xff1a;“赶紧&#xff0c;业务刚通知&#xff0c;我们的官网、小程序、公众号的首页需要变为灰色背景&#xff0c;最好在10点半之前上线”。当时心有千般不愿&#xff0c;但最后生活压倒我坚硬的脊梁。哈哈…

关于《web课程设计》网页设计 用html css做一个漂亮的网站 仿新浪微博个人主页

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

C语言用高斯消元法求行列式

目录 数学原理 程序设计 整体流程与代码 测试函数 测试结果 数学原理 高斯消元法求行列式&#xff1a;利用初等行变换&#xff0c;化为上三角行列式&#xff0c;求其主对角线的乘积 行列式的初等行变换&#xff1a; 1&#xff09;换行变换&#xff1a;交换两行&#xf…

静态路由配置案例

静态路由配置案例配置静态路由原理命令&#xff1a;案例&#xff1a;最后结果&#xff1a;配置静态路由原理命令&#xff1a; [Huawei]ip route-static 来源ip 子网掩码 去向ip [Huawei]ip route-static 192.168.20.1 255.255.255.0 192.168.1.2 案例&#xff1a; pc1,pc2,a…

世界杯里的数学知识

一、前言 2022 年卡塔尔世界杯足球赛已经开幕&#xff0c;这是历史上首次在卡塔尔和中东国家境内举行、也是第二次在亚洲举行的世界杯足球赛。除此之外&#xff0c;卡塔尔世界杯还是首次在北半球冬季举行、首次由从未进过世界杯决赛圈的国家举办的世界杯足球赛。世界杯足球赛里…

凌玮科技IPO注册生效:曾踩雷理财损失2000万元,胡颖妮为董事长

11月30日&#xff0c;广州凌玮科技股份有限公司&#xff08;下称“凌玮科技”&#xff09;在深圳证券交易所创业板递交招股书&#xff08;注册稿&#xff09;。相较于此前招股书&#xff0c;凌玮科技补充披露了截至2022年9月30日的财务数据等信息&#xff0c;并对2022年度的业绩…

SimCSE:对比学习,只需要Dropout

要说2021年上半年NLP最火的论文&#xff0c;想必非《SimCSE: Simple Contrastive Learning of Sentence Embeddings》莫属。SimCSE的全称是Simple Contrastive Sentence Embedding Sentence Embedding Sentence Embedding一直是NLP领域的一个热门问题&#xff0c;主要是因为其…

独家 | AI是如何帮助创造看起来和听起来都和我们一样的仿真数码人的

作者&#xff1a;Anthony Green翻译&#xff1a;顾伟嵩 校对&#xff1a;赵茹萱本文约6000字&#xff0c;建议阅读14分钟 由AI驱动的仿真数码人正在从事娱乐、执法等工作。图来源于ERICA SNYDER/MITTR | UNSPLASH仿真数码双胞胎捕获了真实人类的外表和表情。这些复制品越来越多…

科技云报道:从百度智能云的探索,看懂边缘云的过去和未来

科技云报道原创。 布莱恩阿瑟在《技术的本质》一书中写道&#xff0c;“技术是一个异常美丽的主题&#xff0c;它不动声色地创造了财富&#xff0c;成就了经济的繁荣&#xff0c;改变了人类的生存方式。” 五年前&#xff0c;人们还不会在地铁公交上看视频&#xff0c;因为视频…

obsidian和zotero联动

前言 看了好多obsidian和zotero联动的视频和教程&#xff0c;终于还是下手了。 obsidian和zotero之所有能够完美联动&#xff0c;很大程度上建立在这两个软件都有这活跃的第三方插件市场&#xff0c;只要肯花功夫挖掘&#xff0c;我相信是能玩出花来的。 网上的多数联动是基…

如何在R语言中建立六边形矩阵热图heatmap可视化

原文链接&#xff1a;http://tecdat.cn/?p18879这是一个六边形热图可视化程序&#xff0c;主要用到的知识RColorBrewer&#xff0c;fields,也就是R中的可视化绘图库&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。本文希望SOM的结果以六边形热图可视化。让我…

JMeter入门教程(6) --脚本添加

文章目录1.添加线程组2.添加HTTP Cookie管理器3.添加HTTP请求默认值4.添加HTTP请求5.添加查看结果树1.添加线程组 1.创建JMeter测试计划的第一步就是添加线程组测试元件。线程组会告诉JMeter需要模拟的并发用户数&#xff0c;以及并发用户发送请求的频率和数目。 要添加线程组…

程序过程分析——从编译到执行

汇编源程序 mov ax,4c00H int 21H 这两条指令可以实现程序返回的功能。 编译 使用微软的masm5.0汇编编译器,文件名为masm.exe。 在编译的过程中,我们提供了一个输入,即源程序文件。最多可以得到3个输出:目标文件(.obj)、列表文件(.Ist)、交叉引用文件(.erf),这3个输…