头歌JUnit单元测试相关实验入门

一、入门实验

1.1第一个Junit测试程序

任务描述

请学员写一个名为testSub()的测试函数,来测试给定的减法函数是否正确。

相关知识
Junit编写原则

1、简化测试的编写,这种简化包括测试框架的学习和实际测试单元的编写。 2、测试单元保持持久性。 3、利用既有的测试来编写相关的测试。

Junit特征

1、使用断言方法判断期望值和实际值差异,返回Boolean值

2、测试驱动设备使用共同的初始化变量或者实例。

3、测试包结构便于组织和集成运行。

4、支持图形交互模式和文本交互模式。

Junit框架的组成

1、测试用例(TestCase):对测试目标进行测试的方法与过程的集合

2、测试包(TestSuite):测试用例的集合,可容纳多个测试用例(TestCase)。

3、测试结果(TestResult):测试结果的描述与记录。

4、测试监听(TestListener):测试过程中事件的监听者。

5、测试失败元素(TestFailure):每一个测试方法所发生的与预期不一致状况的描述。

6、测试框架出错异常(AssertionFailedError):junit执行测试时所抛出的异常。

Junit作用介绍

  通常我们写完代码想要测试这段代码的正确性,那么必须新建一个类,然后创建一个 main() 方法,之后再编写测试代码。如果需要测试的代码很多呢?那么要么就会建很多main() 方法来测试,要么将其全部写在一个main()方法里面。这也会大大的增加测试的复杂度,降低程序员的测试积极性。而 Junit 能很好的解决这个问题,简化单元测试,写一点测一点,在之后的代码改动中如果发现问题可以较快的追踪到问题的原因,减小回归错误的纠错难度。

如何编写Junit测试

首先,我们将介绍一个测试类:Calculate.java

//Calculate.java
package com.trustie.junitest;
public class Calculate {public int sum(int var1, int var2) {return var1 + var2;}
}

  在上面的代码中,我们可以看到,Calculate类有一个公共的方法sum(), 它接收输入两个整数,将它们相加并返回结果。在这里,我们将测试这个方法。为了这个目的,我们将创建另一个类及其方法,将测试之前的类(在此情况下,我们只有一个方法进行测试)中的方法,这是使用的最常见的方式。当然,如果一个方法非常复杂且要扩展,我们可以用多个试验方法来对其进行测试。创建测试用例的详细信息将显示在下面的部分。下面,有一个类是:CalculateTest.java,它具有我们的测试类的角色的代码:

// CalculateTest.java
package com.trustie.test;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import com.trustie.junitest.Calculate;public class CalculateTest {// 创建一个Calculate对象Calculate calculation = new Calculate();// 调用sum方法计算2和5的和,并将结果赋值给变量sumint sum = calculation.sum(2, 5);// 定义一个预期的和值int testSum = 7;// 使用@Test注解标记测试方法@Testpublic void testSum() {// 使用assertEquals方法比较实际计算结果和预期结果是否相等assertEquals(sum, testSum);}
}
    先来解释一下上面的代码。首先,我们可以看到,有一个@Test的注解testSum()方法的上方。 这个注释指示该方法它所附着的代码可以做为一个测试用例。因此,testSum()方法将用于测试公开方法 sum() 。 我们再观察一个方法 assertEquals(sum, testsum)    assertEquals ([String message], object expected, object actual) 方法持有两个对象作为输入,并断言这两个对象相等。

然后在Bash执行:

// 编译Calculate.java文件,生成字节码文件
javac -d . Calculate.java// 编译CalculateTest.java文件,生成字节码文件
javac -d . CalculateTest.java// 运行CalculateTest测试类,使用JUnit框架进行单元测试
java org.junit.runner.JUnitCore com.trustie.test.CalculateTest
就可以看到:
JUnit version 4.12
.
Time: 0.003
OK (1 test)
这里首先打印出了JUnit版本号,然后输出了耗时和测试结果。在这里,我们的测试结果是OK,证明测试通过,原函数功能正确。
编程要求

本关的编程任务是在JunitSubTest.java中的补全测试函数testSub(),具体要求:用subtestSub作为参数,来验证JunitSub.javasub函数是否正确的是否正确。

本关涉及的代码文件JunitSub.java的代码如下:

package step1;
public class JunitSub {public int sub(int var1, int var2) {return var1 - var2;}
}
本关涉及的代码文件JunitSubTest.java的代码如下:
package step1;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import step1.JunitSub;
public class JunitSubTest {//引入JunitSub对象JunitSub js = new JunitSub();int sub = js.sub(5,2);int testSub = 3;/*请在下面的Begin/End内写一个测试函数,来验证JunitSub中的sub函数编写是否正确*//***********************Begin**************************//************************End***************************/
}
评测说明

本关卡的测试文件是TestRunner.java,该文件进行了函数封装且学员不可见,用于验证学员的Junit测试代码是否正确。

具体测试过程如下:

1.平台自动编译生成TestRunner.exe;

2.平台运行TestRunner.exe

3.获取TestRunner.exe输出,并将其输出与预期输出对比:如果一致则测试通过,否则测试失败。

预期输入: 预期输出:true

友情提示

1.请不要直接println最终输出,否则平台发现此类情况后,将一律扣掉本关经验值,并且追加处罚措施。

2.学员答题时请尽量手敲代码,请勿从实训讲解代码片段中复制代码段粘贴到答题区域作答,复制的内容会保留一些格式和字符,导致编译失败。

开始你的任务吧,祝你成功!

package step1;import org.junit.Test;
import static org.junit.Assert.assertEquals;
import step1.JunitSub;public class JunitSubTest {//引入JunitSub对象JunitSub js = new JunitSub();int sub = js.sub(5,2);int testSub = 3;/*请在下面的Begin/End内写一个测试函数,来验证JunitSub中的sub函数编写是否正确*//***********************Begin**************************/@Testpublic void testSubFunction() {assertEquals(testSub, sub);}/************************End***************************/}

 1.2Junit注解

相关知识
Junit注解

Java注解((Annotation)的使用方法是"@ + 注解名" 。借助注解,我们可以在编程中通过简单的注解来实现一些功能。在junit中常用的注解有 @Test、@Ignore、@BeforeClass、@AfterClass、@Before、@After 下表列出了这些注释的概括:

具体解释如下:

1、@Test,表明此方法为测试方法。

2、@Before,用此注解修饰的方法在每个test方法运行前执行

3、@BeforeClass,用此注解修饰的方法将在所有方法运行前被执行,是一个static方法,只执行一次。

4、@After,用此注解修饰的方法在每个test方法运行后执行

5、@AfterClass,用此注解修饰的方法将在所有方法运行后被执行,也是一个static方法,只执行一次。

6、@Ignore,用此注解修饰的方法会被Junit忽略。

代码示例

这里新建一个JunitAnnotation.java,把上面所讲的注解全部加到某个测试函数之前,这些注解的作用一目了然:

// 导入JUnit相关的类和静态方法
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;// 定义一个名为AnnotationsTest的公共类,用于进行单元测试
public class AnnotationsTest {// 定义一个私有的ArrayList变量testList,用于存储测试数据private ArrayList testList;// 使用@BeforeClass注解标记的方法,在所有的测试方法执行前只执行一次@BeforeClasspublic static void onceExecutedBeforeAll() {// 输出提示信息System.out.println("@BeforeClass: onceExecutedBeforeAll");}// 使用@Before注解标记的方法,在每个测试方法执行前都会执行一次@Beforepublic void executedBeforeEach() {// 初始化testList为一个新的ArrayList对象testList = new ArrayList();// 输出提示信息System.out.println("@Before: executedBeforeEach");}// 使用@AfterClass注解标记的方法,在所有的测试方法执行后只执行一次@AfterClasspublic static void onceExecutedAfterAll() {// 输出提示信息System.out.println("@AfterClass: onceExecutedAfterAll");}// 使用@After注解标记的方法,在每个测试方法执行后都会执行一次@Afterpublic void executedAfterEach() {// 清空testList中的所有元素testList.clear();// 输出提示信息System.out.println("@After: executedAfterEach");}// 使用@Test注解标记的方法,表示这是一个测试方法@Testpublic void EmptyCollection() {// 断言testList为空,如果为空则测试通过,否则测试失败assertTrue(testList.isEmpty());// 输出提示信息System.out.println("@Test: EmptyArrayList");}// 使用@Test注解标记的方法,表示这是一个测试方法@Testpublic void OneItemCollection() {// 向testList中添加一个元素testList.add("oneItem");// 断言testList的大小为1,如果大小为1则测试通过,否则测试失败assertEquals(1, testList.size());// 输出提示信息System.out.println("@Test: OneItemArrayList");}// 使用@Ignore注解标记的方法,表示这个测试方法被忽略,不会被执行@Ignorepublic void executionIgnored() {// 输出提示信息System.out.println("@Ignore: This execution is ignored");}
}

如果我们运行上面的测试,控制台输出将是下面:

@BeforeClass: onceExecutedBeforeAll
@Before: executedBeforeEach
@Test: EmptyArrayList
@After: executedAfterEach
@Before: executedBeforeEach
@Test: OneItemArrayList
@After: executedAfterEach
@AfterClass: onceExecutedAfterAll
// 在所有测试方法执行前只执行一次的方法
@BeforeClass
public void onceExecutedBeforeAll() {// ...
}// 在每个测试方法执行前都会执行的方法
@Before
public void executedBeforeEach() {// ...
}// 测试方法1:空的ArrayList
@Test
public void EmptyArrayList() {// ...
}// 在每个测试方法执行后都会执行的方法
@After
public void executedAfterEach() {// ...
}// 在每个测试方法执行前都会执行的方法(重复)
@Before
public void executedBeforeEach() {// ...
}// 测试方法2:只有一个元素的ArrayList
@Test
public void OneItemArrayList() {// ...
}// 在所有测试方法执行后只执行一次的方法
@AfterClass
public void onceExecutedAfterAll() {// ...
}
编程要求

本关的编程任务是在JunitAnnotation.java中修改测试函数对应的注解,使得原代码输出结果变为逆序。

本关涉及的代码文件JunitAnnotation.java的代码如下:

见下答案版

评测说明

本关卡的测试文件是TestRunner.java,该文件进行了函数封装且学员不可见,用于验证学员的Junit测试代码是否正确。

具体测试过程如下:

1.平台自动编译生成TestRunner.exe; 2.平台运行TestRunner.exe; 3.获取TestRunner.exe输出,并将其输出与预期输出对比:如果一致则测试通过,否则测试失败。

预期输入: 预期输出:

in after class
in after
in test
in before
in before class
true
package step2;import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;public class JunitAnnotation {/**以下Junit测试程序的输出结果为:*in before class*in before*in test*in after*in after class*请修改下面Begin/End内各个测试函数的注解,使输出结果逆序*//***********************Begin**************************/@BeforeClasspublic static void afterClass() {System.out.println("in after class");}//execute after test@Beforepublic void after() {System.out.println("in after");}//execute before test@Afterpublic void before() {System.out.println("in before");}//execute after class@AfterClasspublic static void beforeClass() {System.out.println("in before class");}//test case@Testpublic void test() {System.out.println("in test");}//execute before class/************************End***************************/
}

 1.3Junit断言

任务描述

给定一个断言测试类AssertionsTest.java,请按要求补全代码,写出相应的断言测试。

相关知识
Junit断言

Junit的断言方法允许检查测试方法的期望结果值和真实返回值。Junit的org.junit.Assert类提供了各种断言方法来写junit测试,这些方法被用来检查方法的真实结果值和期望值。

代码示例

创建一个文件名为 TestAssertions.java 的类,如下:

package com.trustie.junittest;
import org.junit.Test;
import static org.junit.Assert.*;public class TestAssertions {@Testpublic void testAssertions() {//测试数据String str1 = new String ("abc");String str2 = new String ("abc");String str3 = null;String str4 = "abc";String str5 = "abc";int val1 = 5;int val2 = 6;String[] expectedArray = {"one", "two", "three"};String[] resultArray =  {"one", "two", "three"};//检查两个对象是否相等assertEquals(str1, str2);//检查条件是否为真assertTrue (val1 < val2);//检查条件是否为假assertFalse(val1 > val2);//检查对象不为空assertNotNull(str1);//检查对象为空assertNull(str3);//检查两个对象引用是否指向同一个对象assertSame(str4,str5);//检查两个对象引用是否不指向同一个对象assertNotSame(str1,str3);//检查两个数组是否相等assertArrayEquals(expectedArray, resultArray);}
}

在以上类中我们可以看到,这些断言方法是可以工作的。

  • assertEquals() 如果比较的两个对象是相等的,此方法将正常返回;否则失败显示在JUnit的窗口测试将中止。

  • assertSame() 和 assertNotSame() 方法测试两个对象引用指向完全相同的对象。

  • assertNull() 和 assertNotNull() 方法测试一个变量是否为空或不为空(null)。

  • assertTrue() 和 assertFalse() 方法测试if条件或变量是true还是false。

  • assertArrayEquals() 将比较两个数组,如果它们相等,则该方法将继续进行不会发出错误。否则失败将显示在JUnit窗口和中止测试。

编程要求

本关的编程任务是给定一个断言测试类AssertionsTest.java,请按要求补全代码,写出相应的断言测试。

具体要求如下:

1.断言obj1和obj2相等;

2.断言obj3和obj4指向完全相同的对象;

3.断言obj2和obj4指向不同的对象;

4.断言obj1对象不为空;

5.断言obj5对象为空;

6.断言var1小于var2;

7.断言arithmetic1和arithmetic2两个数组相等。

本关涉及的代码文件AssertionsTest.java的代码如下:

见下

评测说明

本关卡的测试文件是TestRunner.java,该文件进行了函数封装且学员不可见,用于验证学员的Junit测试代码是否正确。

具体测试过程如下:

1.平台自动编译生成TestRunner.exe; 2.平台运行TestRunner.exe; 3.获取TestRunner.exe输出,并将其输出与预期输出对比:如果一致则测试通过,否则测试失败。

预期输入: 预期输出:true

package step3;import static org.junit.Assert.*;
import org.junit.Test;public class AssertionsTest {String obj1 = "junit";String obj2 = "junit";String obj3 = "test";String obj4 = "test";String obj5 = null;int var1 = 1;int var2 = 2;int[] arithmetic1 = { 1, 2, 3 };int[] arithmetic2 = { 1, 2, 3 };@Testpublic void test() {//请在下面的Begin/End内写添加断言测试的代码,不要改动其他地方的代码/***********************Begin**************************/assertEquals(obj1,obj2); // 判断两个字符串是否相等assertSame(obj3,obj4); // 判断两个对象引用是否指向同一个对象assertNotSame(obj2,obj4); // 判断两个对象引用是否不指向同一个对象assertNotNull(obj1); // 判断对象引用是否不为空assertNull(obj5); // 判断对象引用是否为空assertTrue (var1 < var2); // 判断一个整数是否小于另一个整数assertArrayEquals(arithmetic1,arithmetic2); // 判断两个数组是否相等/************************End***************************/}
}

1.4Junit时间测试

任务描述

要求学员实现一个Junit时间测试:超过1000毫秒未执行结束就判定测试未通过。

相关知识
Junit时间测试

Junit 提供了一个暂停的方便选项。如果一个测试用例比起指定的毫秒数花费了更多的时间,那么Junit 将自动将它标记为失败。timeout 参数和@Test注释一起使用。现在让我们看看活动中的 @Test(timeout)

代码示例
import org.junit.*;/*** JUnit TimeOut Test*/
public class JunitTest {@Test(timeout = 50000)  //单位是毫秒public void infinity() {  while (true);  // 无限循环,导致测试超时}  
}

在上面的例子中,infinity() 方法将不会返回,因此JUnit引擎将其标记为失败,并抛出一个异常。

java.lang.Exception:test timed out after 50000 milliseconds

编程要求

本关的编程任务是在TestTimeOut.java中实现一个Junit时间测试,超过1000毫秒未执行结束就判定测试未通过。

本关涉及的代码文件TestTimeOut.java的代码如下:

见下述答案

评测说明

本关卡的测试文件是TestRunner.java,该文件进行了函数封装且学员不可见,用于验证学员的Junit测试代码是否正确。

具体测试过程如下:

1.平台自动编译生成TestRunner.exe; 2.平台运行TestRunner.exe; 3.获取TestRunner.exe输出,并将其输出与预期输出对比:如果一致则测试通过,否则测试失败。

预期输入: 预期输出:

test(step4.TestTimeOut): test timed out after 1000 milliseconds
false

package step4;import org.junit.Test;public class TestTimeOut {//请在下面的Begin/End内补全test()超时测试函数,要求如果超过1000毫秒执行未结束,就判定测试未通过/***********************Begin**************************/@Test(timeout = 1000)public void test() {while(true){}}/************************End***************************/
}

 

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

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

相关文章

短线买入卖出有哪些交易技巧?

前面两节课&#xff0c;我们认识了短线交易&#xff0c;知道了短线交易常见的买入卖出时机&#xff0c;这节课&#xff0c;我们来讲解一下短线买入卖出的一些交易技巧。话不多时&#xff0c;直接进入重点&#xff01; 一、短线交易要果断 短线波动快&#xff0c;在出现买卖信号…

排序算法总结(Python、Java)

Title of Content 1 冒泡排序 Bubble sort&#xff1a;两两交换&#xff0c;大的冒到最后概念排序可视化代码实现Python - 基础实现Python - 优化实现Java - 优化实现C - 优化实现C - 优化实现 2 选择排序 Selection sort&#xff1a;第i轮遍历时&#xff0c;将未排序序列中最小…

反序列化漏洞详解(一)

目录 一、php面向对象 二、类 2.1 类的定义 2.2 类的修饰符介绍 三、序列化 3.1 序列化的作用 3.2 序列化之后的表达方式/格式 ① 简单序列化 ② 数组序列化 ③ 对象序列化 ④ 私有修饰符序列化 ⑤ 保护修饰符序列化 ⑥ 成员属性调用对象 序列化 四、反序列化 …

unity学习笔记

一、线段渲染器 在Unity中&#xff0c;线段渲染器&#xff08;Line Renderer&#xff09;是一种用于在场景中绘制线段的组件。线段渲染器非常适合用于创建轨迹、路径、光束等效果。 1. 创建Line Renderer&#xff1a;在Unity编辑器中&#xff0c;你可以通过创建空对象 -> …

Linux - 动态库的加载 和 重谈进程地址空间 - vscode 当中的 Remote - SSH 插件

推书&#xff1a;《现代操作系统》《操作系统--精髓于设计原理》《UNIX环境高级编程》 目录 前言 程序的加载 程序没有加载之前的地址&#xff08;此时还是程序&#xff09; 程序被加载到内存之后&#xff08;此时是进程&#xff09; 动态库的地址 静态库的不加载&#xff…

数据结构——堆排序的topk问题

呀哈喽&#xff0c;我是结衣 前言 今天给大家带来的堆排序的topk问题。topk就是在许多数中&#xff0c;找出前k个大的数&#xff0c;可能是几十个数&#xff0c;也可能是几千万个数中找。今天我们将要在1000000&#xff08;一百万&#xff09;个数中找出前10大的数。 知识点 C…

【c】角谷猜想

#include<stdio.h> int coll(int x)//定义函数 {int count0;while(x>1){if(x%20){xx/2;count;}else{x3*x1;count;}}return count; } int main() {int n,num;scanf("%d",&n);int arr[n1];for(int i1;i<n;i)//输入n组数据保存到数组中{scanf("%d&…

数据结构之哈希表

数据结构之哈希表 文章目录 数据结构之哈希表一、哈希概念二、哈希冲突三、哈希函数常见哈希函数 四、哈希冲突解决闭散列闭散列的思考线性探测线性探测的实现 二次探测 开散列开散列概念开散列的思考开散列实现 五、开散列与闭散列比较 一、哈希概念 顺序结构以及平衡树中&am…

MidJourney笔记(6)-Niji模式

Niji模式 回顾一下,在讲解settings命令时,我们可以看到一个Niji字眼。 而且是在Midjourney V4之后才有的,那Niji到底是什么? Niji是MidJourney中用于绘制二次元/动漫风格的模型,那Niji的V4和V5有什么区别呢?

竞赛选题 : 题目:基于深度学习的水果识别 设计 开题 技术

1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天做一个 基于深度学习的水果识别demo 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/pos…

编程实战:类C语法的编译型脚本解释器(系列)

“脚本”始终是个具有独特魅力的领域&#xff0c;能够随时方便地解决一些问题&#xff0c;但脚本的随意性同时带来别的问题&#xff0c;所以脚本始终属于让人又爱又恨的存在。 很多大型系统都会嵌入一些小型的解释器&#xff0c;用来让用户亲自编写简单的逻辑规则。不幸的是&am…

springCache——jetcache缓存

文章目录 jetcache远程、本地缓存方案jetcache方法注解使用方式 jetcache远程、本地缓存方案 <dependency><groupId>com.alicp.jetcache</groupId><artifactId>jetcache-starter-redis</artifactId><version>2.6.4</version></de…

[c]比较月亮大小

本题的难点就是分情况讨论 #include<stdio.h> int main() {int n;scanf("%d",&n);int arr2[n];int p;for(int m0;m<n-1;m){scanf("%d",&arr2[m]);//输入n个数保存到数组}if(n1)//当输入一个数据时&#xff0c;输入0&#xff0c;可以判断…

Java中实现HTTPS连接的最佳实践

引言 大家好&#xff01;我是小黑。今天咱们来聊聊一个既热门又实用的话题&#xff1a;在Java中如何实现HTTPS连接。现在的网络世界&#xff0c;安全性是大家都非常关注的问题&#xff0c;特别是对于咱们这些程序员来说&#xff0c;更是如此。想想看&#xff0c;如果你的网站或…

【Java 基础】16 泛型

文章目录 什么是泛型&#xff1f;泛型的声明泛型的使用泛型方法通配符和泛型上下界1&#xff09;通配符2&#xff09;泛型上下界 泛型的好处注意事项 泛型提供了一种在编写代码时更好地 支持类型安全的机制。通过泛型&#xff0c;我们可以编写更加 通用、 灵活、 可读性高的…

docker 搭建开发环境,解决deepin依赖问题

本机环境&#xff1a; deepin v23b2 删除docker旧包 sudo apt-get remove docker docker-engine docker.io containerd runc注意卸载docker旧包的时候Images, containers, volumes, 和networks 都保存在 /var/lib/docker 卸载的时候不会自动删除这块数据&#xff0c;如果你先…

Python爬虫完整代码模版——获取网页数据的艺术

Python爬虫完整代码模版——获取网页数据的艺术 在当今数字化世界中&#xff0c;数据是价值的源泉。如何从海量数据中提取所需信息&#xff0c;是每个数据科学家和开发者必须面对的问题。Python爬虫作为一种自动化工具&#xff0c;专门用于从网站上抓取数据。本文将提供一个Py…

YOLOv7+姿态估计Pose+tensort部署加速

YOLOv7-Pose 实现YOLOv7&#xff1a;可训练的免费套件为实时目标检测设置了最新技术标准 YOLOv7-Pose的姿态估计是基于YOLO-Pose的。关键点标签采用MS COCO 2017数据集。 训练 使用预训练模型yolov7-w6-person.pt进行训练。训练命令如下&#xff1a; python -m torch.distr…

Redis 安装

文章目录 第1关&#xff1a;Redis 安装第2关&#xff1a; Redis 启动 第1关&#xff1a;Redis 安装 编程要求 在右侧命令行中在线安装 Redis 服务器软件和客户端软件&#xff1a; 在线安装 Redis&#xff08;实验环境使用的是 Ubuntu 系统&#xff09;&#xff1b; 测试说明…

iptables——建立linux安全体系

目录 一. 安全技术类型 二. linux防火墙 1. 按保护范围划分&#xff1a; 2. 按实现方式划分&#xff1a; 3. 按网络协议划分&#xff1a; 4. 防火墙原理 三. 防火墙工具——iptables 1. netfilter 中五个勾子函数和报文流向 数据包传输过程&#xff1a; ① .五表四链…