JAVA自动化之Junit单元测试框架详解

news2025/4/8 16:04:04

一、JUnit概述&配置

1、Junit是什么?

Junit是一个Java 编程语言的开源测试框架,用于编写和运行测试。官网 地址:https://junit.org/junit4/

2、Maven配置

?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>junit</groupId>
    <artifactId>junitTest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</project>

二、Assertions 断言

JUnit提供了一些辅助的函数,用来判断被测试的方法是否如我们预期的效果一样正常执行。这些辅助函数被称之为断言。
常用断言:

方法示例功能
assertArrayEqualsassertArrayEquals("message", expected, actual);判断两个数组是否相等
assertEqualsassertEquals("message", "text", "text");判断两个对象是否相等
assertFalseassertFalse("failure - should be false", false);判断表达式是否为false
testAssertTrueassertTrue("failure - should be true", true);判断表达式是否为true
assertNotNullassertNotNull("should not be null", new Object());判断是否非空
assertNullassertNull("should be null", null);判断是否为空
assertNotSameassertNotSame("should not be same Object", new Object(), new Object());判断是否为不同对象
assertSameassertSame("should be same", aNumber, aNumber);判断是否为同一对象
..................

三、Test Runners 测试运行器

JUnit中所有的测试方法都是由测试运行器负责执行。当一个类被@RunWith注释或拓展了一个@RunWith注释的类,JUnit将会使用引用的类来执行测试,而不是使用JUnit内置的运行器。

  org.junit.runner.JUnitCore.runClasses(TestClass1.class, ...);

 Specialized Runners:
Suite:Suite是一个标准的运行器,允许手动构建包含来自许多类的测试集。
Parameterized:Parameterized是一个实现参数化测试的标准运行器。运行参数化测试类时,测试方法和测试数据进行合并来创建测试实例。
Categories:Categories运行器来制定分类,定义测试被包含或排除。

四、Aggregating tests in suites 套件

测试套件用于捆绑几个单元测试用例并且一起执行他们,使用@RunWith 和 @Suite 注解。

@RunWith(Suite.class)
@Suite.SuiteClasses({AssertTests.class, CalculatorTest.class})
public class SuiteTest {
    // the class remains empty, used only as a holder for the above annotations
}

五、Test execution order 执行顺序

要改变测试执行的顺序只需要在测试类上使用 @FixMethodOrder注解,并指定一个可用的MethodSorter即可:
@FixMethodOrder(MethodSorters.DEFAULT):JUnit默认使用一个确定的,但不可预测的顺序
@FixMethodOrder(MethodSorters.JVM): 保留测试方法的执行顺序为JVM返回的顺序,每次测试的执行顺序有可能会所不同
@FixMethodOrder(MethodSorters.NAME_ASCENDING):根据测试方法的方法名排序,按照词典排序规则(ASC从小到大递增)

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ExecutionOrderTest {
    @Test
    public void testB() {
        System.out.println("second");
    }
    @Test
    public void testA() {
        System.out.println("first");
    }
    @Test
    public void testC() {
        System.out.println("third");
    }
}

运行结果:

first
second
third

六、Expected Exceptions 异常测试

用于测试某一方法是否抛出了正确的异常。

1、@Test(expected=xxx)方式:当抛出的异常与expected参数指定的异常相同时,测试通过。
2、try...fail...catch...方式:捕捉具体待测语句的异常信息并断言,当没有异常被抛出的时候fail方法会被调用,输出测试失败的信息。
3、ExpectedException Rule方式:使用Rule标记来指定一个ExpectedException,并在测试相应操作之前指定期望的Exception类型。

public class ExpectedExceptionsTest {
    //方法一:@Test(expected=xxx)
    @Test(expected = IndexOutOfBoundsException.class)
    public void empty() {
        new ArrayList<Object>().get(0);
    }
 
    //方法二:try...fail...catch...  当没有异常被抛出的时候fail方法会被调用,输出测试失败的信息。
    @Test
    public void testExceptionMessage() {
        try {
            new ArrayList<Object>().get(0);
            fail("Expected an IndexOutOfBoundsException to be thrown");
        } catch (IndexOutOfBoundsException anIndexOutOfBoundsException) {
            assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0"));
        }
    }
 
    //方法三:在测试之前使用Rule标记来指定一个ExpectedException,并在测试相应操作之前指定期望的Exception类型(如IndexOutOfBoundException.class)
    @Rule
    public ExpectedException thrown = ExpectedException.none();
 
    @Test
    public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
        List<Object> list = new ArrayList<Object>();
        thrown.expect(IndexOutOfBoundsException.class);
        thrown.expectMessage("Index: 0, Size: 0");
        list.get(0);
    }
}

七、Matchers and assertThat

JUnit4.4引入了Hamcrest框架,Hamcest提供了一套匹配符Matcher,这些匹配符更接近自然语言,可读性高,更加灵活。并且使用全新的断言语法assertThat,结合Hamcrest提供的匹配符,只用这一个方法,就可以实现所有的测试。
assertThat语法:
assertThat(T actual, Matcher matcher);
assertThat(String reason, T actual, Matcher matcher);
其中reason为断言失败时的输出信息,actual为断言的值或对象,matcher为断言的匹配器,里面的逻辑决定了给定的actual对象满不满足断言。
Matchers详见:
http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html

八、Ignoring tests 忽略测试

  • 方法用 @Ignore 注解了将不会被执行
  • 类用 @Ignore 注解后,其下所有测试方法将不会被执行
public class IgnoreTest {
    @Ignore("Test is ignored as a demonstration")
    @Test
    public void testSame() {
        assertThat(1, is(1));
    }
}

九、Timeout for tests 超时测试

@Timeout 注解用来测试特定方法的执行时间。如果测试方法的执行时间大于指定的超时参数,测试方法将抛出异常,测试结果为失败。指定的超时参数单位为毫秒
1、@Test注解上的timeout参数,作用域为方法,单位毫秒

@Test(timeout = 2000)
    public void testSleepForTooLong() throws Exception {
        log += "ran1";
        TimeUnit.SECONDS.sleep(100); // sleep for 100 seconds
    }

2、Timeout Rule,作用域为测试类

public class TimeoutTests {
    public static String log;
    private final CountDownLatch latch = new CountDownLatch(1);
 
    @Rule
    public Timeout globalTimeout = Timeout.seconds(3); // 3 seconds max per method tested
 
    @Test
    public void testSleepForTooLong() throws Exception {
        log += "ran1";
        TimeUnit.SECONDS.sleep(100); // sleep for 100 seconds
    }
 
    @Test
    public void testBlockForever() throws Exception {
        log += "ran2";
        latch.await(); // will block
    }
}

十、Parameterized tests 参数化测试

参数化测试允许开发人员使用不同的值反复运行同一个测试。创建参数化测试步骤:

  • 用 @RunWith(Parameterized.class) 来注释 test 类。
  • 创建一个由 @Parameters 注释的公共的静态方法,它返回一个对象的集合(数组)来作为测试数据集合。
  • 创建一个公共的构造函数,接受测试数据。
  • 为每一列测试数据创建一个实例变量。
  • 用实例变量作为测试数据的来源来创建测试用例。

1、Constructor方式
 

@RunWith(Parameterized.class)
public class FibonacciTest {
    @Parameters(name = "{index}: fib({0})={1}")
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
                { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
        });
    }
    private int fInput;
    private int fExpected;
    public FibonacciTest(int input, int expected) {
        this.fInput = input;
        this.fExpected = expected;
    }
    @Test
    public void test() {
        assertEquals(fExpected, Fibonacci.compute(fInput));
    }
}

2、Field injection方式

@RunWith(Parameterized.class)
public class FibonacciTest {
    @Parameters(name = "{index}: fib({0})={1}")
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
                { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
        });
    }
    @Parameter // first data value (0) is default
    public /* NOT private */ int fInput;
    @Parameter(1)
    public /* NOT private */ int fExpected;
    @Test
    public void test() {
        assertEquals(fExpected, Fibonacci.compute(fInput));
    }
}

十一、Assumptions with assume 假定测试

使用Assumptions类中的假设方法时,当假设不成立时会报错,但是测试会显示被ignore忽略执行。也就是当一个类中有多个测试方法时,其中一个假设测试方法假设失败,其他的测试方法全部成功,那么该测试类也会显示测试成功。
假设方法适用于:在不影响测试是否成功的结果的情况下根据不同情况执行相关代码。

public class AssumptionsTest {
    @Test
    public void testAssumTrue() {
        System.out.println("test");
        assumeTrue(3>5);
        //该方法中下面所有的代码在上面假设的条件成立后执行
        //如果上述假设不成立,则会忽略执行该行下面的代码,并报错
        System.out.println("assume is true!");
    }
    @Test
    public void testAssumFalse(){
        assumeFalse(3>5);
        System.out.println("assume is true!");
    }
  }

 以下语法JUnit5支持:

@Test
    public void testAssumTrueMessage() {
        assumeTrue(3<5,
                //第二个参数为当第一个参数不成立时,输出的自定义错误信息
                () -> "Aborting test: not on developer workstation");
        System.out.println("assume is true!");
    }
    @Test
    public void testAssumeTrueLambda(){
        //这个方法的第一个参数为函数式接口,无参数返回值为boolean
        assumeTrue(()->{
            System.out.println("in assumeTrue");
            boolean flag = false;
            return flag;
        });
        System.out.println("out assumeTrue");
    }
    @Test
    public void testAssumThat() {
        assumingThat(3>5,
                () -> {
                    //与上述方法不同的是,仅当前面假设成立时,才会执行这里面的语句
                    //且只会影响到该lambda表达式中的代码
                    assertEquals(2, 2);
                });
        //此处的断言不受上述assumingThat限制,在所有情况下都会执行
        System.out.println("no effect");
        assertEquals("a string", "a string");
    }

十二、Rules 规则

一个JUnit Rule就是一个实现了TestRule的类,用来在每个测试方法的执行前后执行一些代码。
1、框架自带的Rule
JUnit自带很多已经实现过好了的JUnit Rule,比如Timeout,ExpectedException等等。

2、自定义Rule
自定义一个Rule就是implement一个TestRule interface,实现一个叫apply()的方法。
例:在测试方法运行之前,记录测试方法所在的类名和方法名,然后在测试方法运行之后打印出来。

public class MethodNameExample implements TestRule {
    @Override
    public Statement apply(final Statement base, final Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                //base.evaluate()之前为测试方法运行之前所做操作
                String className = description.getClassName();
                String methodName = description.getMethodName();
                //运行测试方法
                base.evaluate();
                //base.evaluate()之后为测试方法运行之后所做操作
                System.out.println("Class name: "+className +", method name: "+methodName);
            }
        };
    }
}

public class RuleTest2 {
    @Rule
    public MethodNameExample methodNameExample = new MethodNameExample();
    @Test
    public void addition_isCorrect() throws Exception {
        assertEquals(4, 2 + 2);
    }
    @Test
    public void mulitiplication_isCorrect() throws Exception {
        assertEquals(4, 2 * 2);
    }
}

十三、Theories

在参数化测试中,我们需要给定所有具体的测试数据组。而在Theories测试中,用户只需给定了一些数据,JUnit自动利用这些数据组合出各种各种可能的组合来执行测试。

1、内置实现

(1)@DataPoints注解静态变量方式

@RunWith(Theories.class)
public class TheoryTest {
    //允许的最大误差
    private static final double DELTA = 0.01;
    /*@DataPoints注解静态变量*/
    @DataPoint
    public static int ZERO = 0;
    @DataPoint
    public static int TWO = 2;
    @DataPoint
    public static int EIGHT = 8;
    //标志这个测试为Theory测试
    @Theory
    public void testDivide(int dividend, int divisor) {
        //跳过除数为0的case
        assumeThat(divisor, not(0));
        //Calculator.divide(dividend, divisor)方法返回他们相除的结果
        assertEquals(dividend / divisor, Calculator.divide(dividend, divisor), DELTA);
        System.out.println("Passed with: dividend=" + dividend + ", divisor=" + divisor);
    }
}

(2)@DataPoints注解静态方法方式

@RunWith(Theories.class)
public class TheoryTest {
    //允许的最大误差
    private static final double DELTA = 0.01;
    /*@DataPoints注解一个静态方法*/
    @DataPoints
    public static int[] getTestData() {
        return new int[]{0, 2, 8};
    }
    //标志这个测试为Theory测试
    @Theory
    public void testDivide(int dividend, int divisor) {
        //跳过除数为0的case
        assumeThat(divisor, not(0));
        //Calculator.divide(dividend, divisor)方法返回他们相除的结果
        assertEquals(dividend / divisor, Calculator.divide(dividend, divisor), DELTA);
        System.out.println("Passed with: dividend=" + dividend + ", divisor=" + divisor);
    }
}

@DataPoint用于注解静态变量(或静态方法),表示这个变量是个数据点。当执行testDivide这个Theory测试时,JUnit会把所有的DataPoint数据两两组合,形成一组组的测试数据,并用这些数据分别执行测试。执行上面的测试会输出以下结果:

Passed with: dividend=0, divisor=2
Passed with: dividend=0, divisor=8
Passed with: dividend=2, divisor=2
Passed with: dividend=2, divisor=8
Passed with: dividend=8, divisor=2
Passed with: dividend=8, divisor=8

 (3)如果需要限定某个参数,可以使用@TestOn注解

import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.experimental.theories.suppliers.TestedOn;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
@RunWith(Theories.class)
public class TheoryTest {
    //允许的最大误差
    private static final double DELTA = 0.01;
    //如果需要限定某个参数,可以使用@TestOn注解
    @Theory
    public void testDivide2(
            @TestedOn(ints = {0, 2, 8}) int dividend,
            @TestedOn(ints = {2, 8}) int divisor
    ) {
        assertEquals(dividend / divisor, Calculator.divide(dividend, divisor), DELTA);
        System.out.println("Passed with: dividend=" + dividend + ", divisor=" + divisor);
    }
}

2、自定义实现

JUnit默认只提供了一个int型的简单 Parameter Supplier 实现,而Theory机制真正的价值在于,能参考@TestedOn的做法,相对简单的完全自定义出可重用 Parameter Supplier,适应于各种复杂要求的限定范围参数值测试场景,满足开发者所需的高度动态自定义范围取值自动化测试,同时保留与一般@Test相同的强大兼容性。
例:
(1)定义annotation注解接口Between
 

@Retention(RetentionPolicy.RUNTIME)
// 声明注解接口所使用的委托处理类
@ParametersSuppliedBy(BetweenSupplier.class)
public @interface Between{
    // 声明所有可用参数,效果为 @Between([first = int,] last = int)
    int first() default 0;  // 声明默认值
    int last();
}

(2)定义委托处理类 BetweenSupplier

public class BetweenSupplier extends ParameterSupplier {
    @Override
    public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
        // 自定义实参值列表
        List<PotentialAssignment> list = new ArrayList<PotentialAssignment>();
        // 获取注解变量
        Between between = sig.getAnnotation(Between.class);
        // 获取通过注解@Between传入的first值
        int first = between.first();
        // 获取通过注解@Between传入的last值
        int last = between.last();
        for (int i = first; i <= last; i++) {
            // PotentialAssignment.forValue(String name, Object value)
            // name为value的描述标记,没实际作用
            // value为实参可选值
            list.add(PotentialAssignment.forValue("name", i));
        }
        return list;
    }
}

(3)调用方式

@RunWith(Theories.class)
public class TheoryDefinedTest {
    @Theory
    public final void test(@Between(last = 0) int i, @Between(first = 3, last= 10) int j) {
        // i 取值为 0(first默认=0,last=0),j 取值为 3-10
        System.out.println("i="+i+"  j="+j);
    }
}

(4)运行结果

i=0  j=3
i=0  j=4
i=0  j=5
i=0  j=6
i=0  j=7
i=0  j=8
i=0  j=9
i=0  j=10

十四、Test fixtures

Test Fixture是指一个测试运行所需的固定环境,也是就是测试运行之前所需的稳定的、公共的可重复的运行环境,这个“环境”不仅可以是数据,也可以指对被测软件的准备,例如实例化被测方法所依赖的类、加载数据库等等。

  • @Before - 在每个@Test方法之前运行
  • @After - 在每个@Test方法之后运行
  • @BeforeClass - 在所有的@Test方法之前运行一次
  • @AfterClass - 在所有的@Test方之后运行一次
    注:

1、如果创建一个子类继承有fixture注解的父类,那么子类中的@Before方法会在测试方法之前、父类的@Before执行之后执行。
2、如果@Before方法里抛出了异常,@Test方法会跳过,但是@After还是会执行
3、每个测试方法都会在单独的测试类的实例里面运行,@BeforeClass在测试实例创建之前执行
 

public class FixtureTest {
    private static int quantity = 0;
    public FixtureTest() {
        quantity++;
    }
    @BeforeClass
    public static void breforeTestOnlyOnce() throws Exception {
        System.out.println("Run before all test only once..."+ quantity);
    }
    @AfterClass
    public static void afterTestOnlyOnce() throws Exception {
        System.out.println("Run after all test only once..."+ quantity);
    }
    @Before
    public void beforePerTest() {
        System.out.println("Run before per test ..."+ quantity);
    }
    @After
    public void afterPerTest() {
        System.out.println("Run after per test ..."+ quantity);
    }
    //Test Method
    @Test
    public void testOne() {
        System.out.println("testOne Start..."+ quantity);
    }
    @Test
    public void testTwo() {
        System.out.println("testTwo Start..."+ quantity);
    }
}

运行结果:

Run before all test only once...0
Run before per test ...1
testOne Start...1
Run after per test ...1
Run before per test ...2
testTwo Start...2
Run after per test ...2
Run after all test only once...2

十五、Categories 用例分类

category 和 testSuite的比较:testSuite是类级分组(xx.class),category是用例级分组(@Test),category是testSuite的升级
category使用步骤:
1、创建好测试类,及测试类中的测试用例
2、创建接口:按用例的分组来创建
3、@Category注解:将用例用@Category注解分组
4、创建类来执行这些分组的类

public interface FastTests { /* category marker */ }
public interface SlowTests { /* category marker */ }
 
public class A {
  @Test
  public void a() {
    fail();
  }
  @Category(SlowTests.class)
  @Test
  public void b() {
  }
}
 
@Category({SlowTests.class, FastTests.class})
public class B {
  @Test
  public void c() {
  }
}
 
@RunWith(Categories.class)
@IncludeCategory(SlowTests.class)
@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
public class SlowTestSuite {
  // Will run A.b and B.c, but not A.a
}
 
@RunWith(Categories.class)
@IncludeCategory(SlowTests.class)
@ExcludeCategory(FastTests.class)
@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
public class SlowTestSuite {
  // Will run A.b, but not A.a or B.c
}

十六、总结

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

 

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取   

 

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

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

相关文章

一文搞懂模板(template)

背景引入&#xff1a; 想象一下&#xff0c;我们要实现一个整数相加&#xff0c;浮点数相加的函数&#xff0c;如果按C语言的思路&#xff0c;我们需要写两个函数名不同的函数&#xff0c;来完成相加&#xff1b;如果C语言&#xff0c;则可以通过函数重载的特性&#xff0c;写两…

LC1305. 两棵二叉搜索树中的所有元素(JAVA)

两棵二叉搜索树中的所有元素 题目描述中序遍历 归并排序 题目描述 难度 - 中等 LC1305. 两棵二叉搜索树中的所有元素 给你 root1 和 root2 这两棵二叉搜索树。请你返回一个列表&#xff0c;其中包含 两棵树 中的所有整数并按 升序 排序。. 示例1&#xff1a; 输入&#xff1a;…

燃气安全如何保障?万宾燃气管网监测系统时刻感知管网运行态势

近年来随着我国城镇化建设的加快&#xff0c;燃气已经成为每个家庭的必需品。然而&#xff0c;每年夏季频繁发生的燃气爆炸事故&#xff0c;已经严重危害人民生命财产安全危害社会公共安全和公共利益。为了保障燃气安全运行&#xff0c;近日&#xff0c;许多城市都在大力推进燃…

Redis代码实践总结(二)

使用 CLI 探索 Redis 外部程序使用 TCP 套接字和 Redis 特定协议与 Redis 进行通信。该协议在不同编程语言的 Redis 客户端库中实现。然而&#xff0c;为了使使用 Redis 进行黑客攻击变得更简单&#xff0c;Redis 提供了一个命令行实用程序&#xff0c;可用于向 Redis 发送命令…

Docker配置镜像加速器

1.登录阿里云 阿里云-计算&#xff0c;为了无法计算的价值 (aliyun.com) 2.容器 说明&#xff1a;找到产品下的容器 3.容器镜像服务ACR 4.点击控制台 5. 点击镜像加速器 6.操作文档

项目开发过程中,成员提离职,怎么办?

之前写过一篇《如何应对核心员工提离职》反响特别好&#xff0c;今天做个延展篇&#xff0c;在项目过程中&#xff0c;员工突然提离职&#xff0c;我们有什么办法让项目按时按质的上线。 项目做多了&#xff0c;总会碰到这种情况。这里给大家介绍一个解决项目问题的分析方法&a…

【0223】源码剖析smgr底层设计机制(3)

1. smgr设计机制 PG内核中smgr完整磁盘存储介质的管理是通过下面三部分实现的。 1.1 函数指针结构体 f_smgr 函数指针结构体 f_smgr。 通过该函数指针类型,可完成类似于UNIX系统中的VFD功能,上层只需要调用open()、read()、write()等系统函数,用户不必去关系底层的文件系统…

Git那些事系列:从业务场景到高级技巧的完整指南(三)

文件修改的记录居然没有了&#xff01;&#xff01;&#xff01; 如何隐蔽的把一次修改记录搞丢&#xff01; 大家好&#xff0c;有到了Git那些事系列了&#xff0c;近期笔者遇到了一个十分奇怪的事情&#xff0c;一个Git仓库的文件被莫名其妙的修改了&#xff0c;问题是&…

1、SpringBoot_快速入门

一、SpringBoot 概述 文档下载地址&#xff1a;https://docs.spring.io/spring-boot/docs/current/reference/ 1.SpringBoot介绍 概述&#xff1a;SpringBoot 开发团队认为Spring操作太繁琐了&#xff0c;目的在于简化开发配置&#xff0c;能够快速搭建开发环境&#xff0c;…

25422-2010 草地潜松犁 阅读笔记

声明 本文是学习GB-T 25422-2010 草地潜松犁. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了草地潜松犁(以下简称潜松犁)的技术要求、试验方法、检验规则、标志、包装与贮存。 本标准适用于在草地上进行不翻垡松土、切根等项作…

RK3588 VDD_CPU_BIG0/1 电源PCB设计注意事项

RK3588 VDD_CPU_BIG0/1 电源PCB设计 1、如图1所示的滤波电容&#xff0c;原理图上靠近 RK3588的VDD_CPU_BIG电源管脚绿线以内的去耦电容务必放在对应的电源管脚背面&#xff0c;电容GND PAD尽量靠近芯片中心的GND管脚放置&#xff0c;如图2所示。其余的去耦电容尽量摆放在3588…

python学习--特殊方法和属性

名称描述特殊属性dict获得类对象或实例对象所绑定的所有属性和方法的字典特殊方法len()通过重写_len_()方法&#xff0c;让内置函数len()的参数可以是自定义的类型特殊方法add()通过重写_add_()方式&#xff0c;&#xff0c;可使自定义对象有‘’的功能特殊方法new()用于创建对…

overleaf杂谈-Springer文献格式问题

目录 overleaf写作问题记录1.Latex中的%问题&#xff08;文本变成灰色&#xff09;2.Springer文献格式问题2.1 新建reference.bib2.2 谷歌学术搜索文章并引用2.3 复制BibTex2.4 复制进reference.bib2.5 在sn-article.tex的\end{document}前添加语句2.6 引用文献2.7 Springer模板…

视频下载器助手:如何把微信视频号的视频下载下来

随着移动互联网的飞速发展&#xff0c;短视频已深入人心&#xff0c;成为我们生活中不可或缺的一部分。我们常常在各种社交平台上发现有趣、有价值的视频内容&#xff0c;但不知道如何把微信视频号的视频下载下来并保存到本地手机相册 今天&#xff0c;我为大家带来了一款实用…

C语言每日一题(11):杨辉三角

文章主题&#xff1a;求两个数二进制中不同位的个数&#x1f525;所属专栏&#xff1a;C语言每日一题&#x1f4d7;作者简介&#xff1a;每天不定时更新C语言的小白一枚&#xff0c;记录分享自己每天的所思所想&#x1f604;&#x1f3b6;个人主页&#xff1a;[₽]的个人主页&a…

SAP ABAP端实现解析具有深层结构的文件内容(类似SAP PO中的FCC功能)

前言 日本项目经常需要通过PI或者CPI去解析一些文件内容&#xff0c;如果只是扁平结构的&#xff0c;不涉及头行结构的话&#xff0c;在PI中可以FCC&#xff08;File Content Conversion&#xff09;进行解析转换&#xff0c;在CPI中可以使用groovy脚本进行解析转换&#xff0…

如何试用 Vectorizer.AI 将位图转换为矢量图

Vectorizer.AI 是一个使用人工智能技术将位图转换为矢量图的在线工具。它支持 JPEG、PNG、BMP 和 GIF 格式的位图&#xff0c;最大像素为 2 万像素&#xff0c;最大文件大小为 30 MB。Vectorizer.AI 目前处于测试阶段&#xff0c;完全免费使用。 要试用 Vectorizer.AI&#xf…

【微服务】spring 控制bean加载顺序使用详解

目录 一、前言 二、使用order注解控制顺序 2.1 order 注解使用示例 2.2 order注解顺序失效问题 2.2.1 order失效问题解决办法 2.3 实现Ordered接口 三、使用dependon注解控制顺序 四、AutoConfiguration注解控制bean加载顺序 4.1 AutoConfigureBefore 操作演示 4.2 A…

进程与线程的记忆方法

有很多人经常会分不清进程与线程的关系&#xff0c; 嗯。。。。。。可能只有我自己记不清吧 举个例子&#xff1a; 进程&#xff1a;登录一个qq号&#xff0c;就是一个进程。 线程&#xff1a;同时打开多个窗口聊天&#xff0c;就是多个线程。 每次记忆完&#xff0c;过了一段…

Python函数绘图与高等代数互融实例(六): 条形图|直方图|饼状图|并列柱状图

Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数 Python函数绘图与高等代数互融实例(二):闪点函数 Python函数绘图与高等代数互融实例(三):设置X|Y轴|网格线 Python函数绘图与高等代数互融实例(四):设置X|Y轴参考线|参考区域 Python函数绘图与高等代数互融实例(五…