[嵌入式系统-72]:RT-Thread-组件:单元测试框架utest

目录

utest 测试框架

​编辑

测试用例定义

测试单元定义

utest 应用框图

2. utest API

assert 宏

测试单元函数运行宏

测试用例导出宏

测试用例 LOG 输出接口

3. 配置使能

4. 应用范式

5. 测试用例运行要求

6. 运行测试用例

测试结果分析

7. 测试用例运行流程

8. 注意事项


utest 测试框架

utest(unit test)是 RT-Thread 开发的单元测试框架。设计 utest 的初衷是方便 RT-Thread 开发者使用统一的框架接口编写测试程序,实现单元测试、覆盖测试以及集成测试的目的。

测试用例定义

测试用例(testcase,简称 tc)是为实现特定测试目标而执行的单个测试,是包括测试输入、执行条件、测试过程和预期结果的规范,是一个有明确的结束条件明确的测试结果的有限循环。

utest(unit test)测试框架定义用户编写的测试程序为测试用例,一个测试用例仅包含一个 testcase 函数(类似 main 函数),可包含多个测试单元函数。

具体地通过 utest 测试框架提供的 API 完成的针对某一功能的测试代码就是一个测试用例。

测试单元定义

测试单元(test unit)是被测功能细分后的测试点,每个测试点可以任务是被测功能的最小可测单位。当然,不同的分类方式会细分出不同的测试单元。

utest 应用框图

utest 应用框图

如上图所示,测试用例基于测试框架 utest 测试框架提供的服务接口进行程序设计,支持将多个测试用例编译到一起进行测试

另外从图中可以看到,一个测试用例对应唯一的 testcase 函数,在 testcase 中包含多个测试单元(test unit)。

在RT Thread中使用utest进行单元测试的优点主要体现在以下几个方面:

  1. 提高代码质量:单元测试可以帮助开发人员确保每个模块或代码单元都按照预期工作,从而提高代码的整体质量。通过utest,开发人员可以在代码集成到整个系统之前,就发现并修复潜在的问题。
  2. 早期发现错误:utest允许在开发早期就进行错误检测,这意味着问题可以在其影响范围扩大之前就被发现。这有助于减少修复错误的成本,并提高开发效率。
  3. 简化调试过程:由于单元测试关注的是代码的最小可测单元,因此当测试失败时,开发人员可以更容易地定位问题所在。与集成测试或系统测试相比,单元测试的调试过程通常更为简单和直接。
  4. 促进模块化设计:通过编写单元测试,开发人员需要更仔细地考虑代码的结构和设计。这有助于促进模块化设计,使得代码更易于理解、维护和扩展。
  5. 增强代码可维护性:一旦为代码编写了单元测试,那么当未来对代码进行修改或重构时,就可以通过运行这些测试来验证代码是否仍然按预期工作。这有助于确保代码的可维护性,并减少因修改而引入新错误的风险。
  6. 持续集成和自动化测试:utest可以与持续集成(CI)工具(如Jenkins)结合使用,实现自动化测试。这意味着每次代码更改时,都可以自动运行测试,从而确保代码更改不会引入新的问题。这有助于保持代码库的健康和稳定。
  7. 跨平台兼容性测试:在RT Thread这样的嵌入式系统中,跨平台兼容性是一个重要的问题。通过utest,开发人员可以在不同的硬件和操作系统上运行测试,以确保代码的跨平台兼容性。

总之,使用utest进行单元测试是RT Thread开发中的一个重要实践,它可以帮助开发人员提高代码质量、早期发现错误、简化调试过程、促进模块化设计、增强代码可维护性、实现持续集成和自动化测试以及进行跨平台兼容性测试。

在RT Thread中进行单元测试,使用utest的好处主要体现在以下几个方面:

  1. 结构化和组织化:utest提供了一个统一的框架和接口,使得测试代码更加结构化和组织化。这有助于开发人员更好地管理、维护和扩展测试代码。
  2. 简化测试过程:utest测试框架提供了丰富的API和工具,使得编写和运行测试用例变得更加简单和高效。开发人员可以更加专注于测试逻辑本身,而无需过多关注测试环境的搭建和测试数据的准备。
  3. 提高测试效率:通过utest,开发人员可以编写可复用的测试代码,避免重复编写相似的测试逻辑。此外,utest还支持并发测试,可以同时运行多个测试用例,进一步提高测试效率
  4. 测试结果的可视化:utest通常与测试结果报告工具集成,可以将测试结果以图表、报告等形式展示,使得测试结果更加直观和易于理解。这有助于开发人员快速定位和解决问题。
  5. 便于持续集成和自动化测试:utest可以与持续集成(CI)工具(如Jenkins)结合使用,实现自动化测试。这意味着每次代码更改时,都可以自动运行测试,从而确保代码更改不会引入新的问题。这有助于保持代码库的健康和稳定。

至于为什么不直接写测试代码,原因有以下几点:

  1. 可维护性和可扩展性:直接编写测试代码可能会导致测试代码与业务代码紧密耦合,难以维护和扩展。而使用utest这样的测试框架,可以将测试代码与业务代码分离,使得测试代码更加独立和可维护。
  2. 测试质量:utest测试框架提供了丰富的测试功能和工具,可以确保测试代码的准确性和完整性。直接编写测试代码可能会遗漏一些重要的测试场景或条件,导致测试结果不准确。
  3. 测试效率:使用utest可以提高测试效率。通过编写可复用的测试代码和并发测试,可以缩短测试时间并提高测试覆盖率。而直接编写测试代码可能会浪费大量的时间和精力在重复编写相似的测试逻辑上。

因此,使用utest进行单元测试可以带来诸多好处,包括提高测试效率、确保测试质量、简化测试过程等。这些好处使得utest成为RT Thread中进行单元测试的重要工具之一。

2. utest API

为了能够实现格式统一的测试用例代码,测试框架 utest 为测试用例编写提供了一套通用的 API 接口。

assert 宏

注意:
这里的 assert 仅记录通过和失败的数量,不会产生断言并终止程序运行。其功能不等同于 RT_ASSERT。复制错误复制成功
assert 宏说明
uassert_true(value)value 为 true 则测试通过,否则测试失败
uassert_false(value)value 为 false 则测试通过,否则测试失败
uassert_null(value)value 为 null 则测试通过,否则测试失败
uassert_not_null(value)value 为非 null 值则测试通过,否则测试失败
uassert_int_equal(a, b)a 和 b 值相等则测试通过,否则测试失败
uassert_int_not_equal(a, b)a 和 b 值不相等则测试通过,否则测试失败
uassert_str_equal(a, b)字符串 a 和字符串 b 相同则测试通过,否则测试失败
uassert_str_not_equal(a, b)字符串 a 和字符串 b 不相同则测试通过,否则测试失败
uassert_in_range(value, min, max)value 在 min 和 max 的范围内则测试通过,否则测试失败
uassert_not_in_range(value, min, max)value 不在 min 和 max 的范围内则测试通过,否则测试失败

测试单元函数运行宏

UTEST_UNIT_RUN(test_unit_func)复制错误复制成功

测试用例中,使用 UTEST_UNIT_RUN 宏执行指定的测试单元函数 test_unit_func

测试单元(test unit)必须使用 UTEST_UNIT_RUN 宏执行。

测试用例导出宏

UTEST_TC_EXPORT(testcase, name, init, cleanup, timeout)复制错误复制成功
参数描述
testcase测试用例主承载函数(规定使用名为 static void testcase(void) 的函数
name测试用例名称(唯一性)。规定使用测试用例相对 testcases 目录的相对路径以 . 进行连接的命名格式
init测试用例启动前的初始化函数
cleanup测试用例结束后的清理函数
timeout测试用例预计需要的测试时间(单位是秒)

测试用例命名要求:

测试用例需要按照规定的格式命名。规定使用当前测试用例相对 testcases 目录的相对路径以 . 进行连接的命名格式,名字中包含当前测试用例文件的文件名(除去后缀名的文件名)。

测试用例命名示例:

假设在测试用例 testcases 目录下,有 testcases\components\filesystem\dfs\dfs_api_tc.c 测试用例文件,那么该 dfs_api_tc.c 中的测试用例的名称命名为 components.filesystem.dfs.dfs_api_tc

测试用例 LOG 输出接口

utest 测试框架依赖 ulog 日志模块进行日志输出,并且 utest 测试框架中已经日志输出级别。因此只要在测试用例里加入 #include "utest.h" 即可使用 ulog 日志模块的所有级别接口(LOG_D/LOG_I/LOG_E)。

另外,utest 测试框架增加了额外的日志控制接口,如下:

#define UTEST_LOG_ALL    (1u)
#define UTEST_LOG_ASSERT (2u)

void utest_log_lv_set(rt_uint8_t lv);复制错误复制成功

用户可以在测试用例中使用 utest_log_lv_set 接口控制日志输出级别。UTEST_LOG_ALL 配置输出所有日志,UTEST_LOG_ASSERT 配置仅输出 uassert 失败后的日志。

3. 配置使能

使用 utest 测试框架需要在 ENV 工具中使用 menuconfig 进行如下配置:

RT-Thread Kernel  --->
    Kernel Device Object  --->
        (256) the buffer size for console log printf /* utest 日志需要的最小 buffer */
RT-Thread Components  --->
    Utilities  --->
        -*- Enable utest (RT-Thread test framework) /* 使能 utest 测试框架 */
        (4096) The utest thread stack size          /* 设置 utest 线程堆栈(-thread 模式需要) */
        (20)   The utest thread priority            /* 设置 utest 线程优先级(-thread 模式需要) */复制错误复制成功

4. 应用范式

前面介绍了 utest 测试框架和相关 API,这里介绍基本的测试用例代码结构

测试用例文件必须的代码块如下所示:

/*
 * Copyright (c) 2006-2019, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-01-16     MurphyZhao   the first version
 */

#include <rtthread.h>
#include "utest.h"

static void test_xxx(void)
{
    uassert_true(1);
}

static void test_xxx(void) 
{ 
    uassert_true(yyy());   //测试某个函数运行的结果是否正确
}

static rt_err_t utest_tc_init(void) //运行测试用例前的初始化
{
    return RT_EOK;
}

static rt_err_t utest_tc_cleanup(void) //运行测试例后的清除操作
{
    return RT_EOK;
}

static void testcase(void)    //一个测试用例,可以包含多个测试单元
{
    UTEST_UNIT_RUN(test_xxx); //测试单元,可以有多个测试单元
}
UTEST_TC_EXPORT(testcase, "components.utilities.utest.sample.sample_tc", utest_tc_init, utest_tc_cleanup, 10);
复制错误复制成功

备注:

测试用例的名字,并不是测试用例的源代码的文件名称,而是通过UTEST_TC_EXPORT制定的名称!!!

一个基本的测试用例必须包含以下内容:

  • 文件注释头(Copyright)

    测试用例文件必须包含文件注释头,包含 Copyright、时间、作者、描述信息。

  • utest_tc_init(void)

    测试运行前的初始化函数,一般用来初始化测试需要的环境

  • utest_tc_cleanup(void)

    测试结束后的清理函数,用来清理测试过程中申请的资源(如内存,线程,信号量等)。

  • testcase(void)

    测试主体函数,一个测试用例实现仅能包含一个 testcase 函数(类似 main 函数)。通常该函数里只用来运行测试单元执行函数 UTEST_UNIT_RUN 。一个测试用例函数可以通过多个UTEST_UNIT_RUN 运行多个测试单元。

    一个 testcase 中可以包含多个测试单元,每个测试单元由 UTEST_UNIT_RUN 执行。

  • UTEST_UNIT_RUN

    测试单元执行函数。运行一次测试单元对应的函数。

  • test_xxx(void)

    每个功能单元的测试实现。用户根据需求确定函数名和函数实现。

  • uassert_true

    用于判断测试结果的断言宏(该断言宏并不会终止程序运行)。测试用例必须使用 uassert_xxx 宏来判断测试结果,否则测试框架不知道测试是否通过。

    所有的 uassert_xxx 宏都通过后,整个测试用例才算测试通过。

  • UTEST_TC_EXPORT

    将测试用例 testcase 函数导出到测试框架中,这样就可以通过测试用例框架执行该测试用来了!!!

UTEST_UNIT_RUN本身并不会直接启动一个线程来运行程序测试单元。UTEST_UNIT_RUN(或类似的宏/函数)是用于在UTest测试框架中定义一个测试单元(test unit)的。这个宏/函数的作用是将你的测试代码封装成一个可执行的测试单元,但具体的执行方式(例如是否作为线程运行)则取决于UTest测试框架的实现以及你的测试策略。

在UTest中,测试单元通常被定义为一个包含测试代码的函数。当你调用UTEST_UNIT_RUN(或类似的宏/函数)来运行测试时,UTest测试框架会按照你定义的测试单元来执行测试代码。这些测试代码可以是在主线程中顺序执行,也可以是在多个线程中并发执行,具体取决于你的测试策略和实现方式。

如果你在RT-Thread这样的实时操作系统环境中使用UTest,并且想要将测试单元作为线程来运行,那么你可能需要自己在代码中创建线程,并在线程函数中调用UTEST_UNIT_RUN来运行测试单元。这样做的好处是可以实现测试的并发执行,提高测试效率。但是,你也需要注意线程同步和通信的问题,以确保测试的正确性和稳定性。

5. 测试用例运行要求

测试框架 utest 将所有的测试用例导出到了 UtestTcTab 代码段,在 IAR 和 MDK 编译器中不需要在链接脚本中定义 UtestTcTab 段,但是在 GCC 编译时,需要在链接脚本中显式地设置 UtestTcTab 段。

因此,测试用例要在 GCC 下能够编译运行,必须要先在 GCC 的链接脚本中定义 UtestTcTab 代码段。

在 GCC 链接脚本的 .text 中,增加 UtestTcTab 段的定义,格式如下所示:

/* section information for utest */
. = ALIGN(4);
__rt_utest_tc_tab_start = .;
KEEP(*(UtestTcTab))
__rt_utest_tc_tab_end = .;复制错误复制成功

6. 运行测试用例

测试框架提供了以下命令,便于用户在 RT-Thread MSH 命令行中运行测试用例,命令如下:

utest_list 命令

列出当前系统支持的测试用例,包括测试用例的名称和测试需要的时间。该命令无参数。

utest_run 命令

测试用例执行命令,该命令格式如下:

utest_run [-thread or -help] [testcase name] [loop num]复制错误复制成功
utest_run 命令参数描述
-thread使用线程模式运行测试框架,否则,在msh线程中运行测试用例
-help打印帮助信息
testcase name指定测试用例名称。支持使用通配符*,支持指定测试用例名称前部分字节
loop num指定测试用例循环测试次数,可以多长执行某个测试用例

UTEST_UNIT_RUN本身并不会直接启动一个线程来运行程序测试单元。UTEST_UNIT_RUN(或类似的宏/函数)是用于在UTest测试框架中定义一个测试单元(test unit)的。这个宏/函数的作用是将你的测试代码封装成一个可执行的测试单元,但具体的执行方式(例如是否作为线程运行)则取决于UTest测试框架的实现以及你的测试策略。

在UTest中,测试单元通常被定义为一个包含测试代码的函数。当你调用UTEST_UNIT_RUN(或类似的宏/函数)来运行测试时,UTest测试框架会按照你定义的测试单元来执行测试代码。这些测试代码可以是在主线程中顺序执行,也可以是在多个线程中并发执行,具体取决于你的测试策略和实现方式。

如果你在RT-Thread这样的实时操作系统环境中使用UTest,并且想要将测试单元作为线程来运行,那么你可能需要自己在代码中创建线程,并在线程函数中调用UTEST_UNIT_RUN来运行测试单元。这样做的好处是可以实现测试的并发执行,提高测试效率。但是,你也需要注意线程同步和通信的问题,以确保测试的正确性和稳定性。

测试命令使用示例:

msh />utest_list
[14875] I/utest: Commands list :
[14879] I/utest: [testcase name]:components.filesystem.dfs.dfs_api_tc; [run timeout]:30
[14889] I/utest: [testcase name]:components.filesystem.posix.posix_api_tc; [run timeout]:30
[14899] I/utest: [testcase name]:packages.iot.netutils.iperf.iperf_tc; [run timeout]:30

备注:当前,在utest测试框架中,注册了3个测试用例,可以借助utest框架,用utest_run直接运行着3个测试用例。

msh />

msh />utest_run components.filesystem.dfs.dfs_api_tc
[83706] I/utest: [==========] [ utest    ] started
[83712] I/utest: [----------] [ testcase ] (components.filesystem.dfs.dfs_api_tc) started
[83721] I/testcase: in testcase func...
[84615] D/utest: [    OK    ] [ unit     ] (test_mkfs:26) is passed
[84624] D/testcase: dfs mount rst: 0
[84628] D/utest: [    OK    ] [ unit     ] (test_dfs_mount:35) is passed
[84639] D/utest: [    OK    ] [ unit     ] (test_dfs_open:40) is passed
[84762] D/utest: [    OK    ] [ unit     ] (test_dfs_write:74) is passed
[84770] D/utest: [    OK    ] [ unit     ] (test_dfs_read:113) is passed
[85116] D/utest: [    OK    ] [ unit     ] (test_dfs_close:118) is passed
[85123] I/utest: [  PASSED  ] [ result   ] testcase (components.filesystem.dfs.dfs_api_tc)
[85133] I/utest: [----------] [ testcase ] (components.filesystem.dfs.dfs_api_tc) finished
[85143] I/utest: [==========] [ utest    ] finished

备注:
测试框架会按照自己的格式和顺序,以及是否启动独立线程的设置,运行测试用例,并把测试结果按照特定的格式显示出来。

msh />复制错误复制成功

测试结果分析

utest 日志展示

如上图所示,测试用例运行的日志从左到右被分成了四列,分别是 log 日志头信息、结果栏、属性栏、详细信息展示栏。

日志中使用 result 属性标识该测试用例测试结果(PASSED or FAILED)。

7. 测试用例运行流程

测试用例运行流程

从上面的流程图中可以得到以下内容:

  • utest 测试框架是顺序执行 testcase 测试用例函数中的所有测试单元(函数调用)
  • 上一个 UTEST_UNIT_RUN 宏执出现了 assert,后面的所有 UTEST_UNIT_RUN 会跳过执行

8. 注意事项

Note

注:- 使用 GCC 编译前,确定链接脚本是否增加了 UtestTcTab 段 - 编译前确保 RT-Thread Kernel -> Kernel Device Object -> (256) the buffer size for console log printf 至少为 256 字节 - 测试用例中创建的资源(线程、信号量、定时器、内存等)需要在测试结束前释放 - 一个测试用例实现仅能使用 UTEST_TC_EXPORT 导出一个测试主体函数(testcase 函数) - 为编写的测试用例程序编写 README.md 文档,指导用户配置测试环境

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RAG 场景对Milvus Cloud向量数据库的需求

虽然向量数据库成为了检索的重要方式,但随着 RAG 应用的深入以及人们对高质量回答的需求,检索引擎依旧面临着诸多挑战。这里以一个最基础的 RAG 构建流程为例:检索器的组成包括了语料的预处理如切分、数据清洗、embedding 入库等,然后是索引的构建和管理,最后是通过 vecto…

webpack从零到1 构建 vue3

为什么要手写webpack 不用cli &#xff08;无的放矢&#xff09;并不是 其实是为了加深我们对webpack 的了解方便以后灵活运用webpack 的技术 初始化项目结构&#xff08;跟cli 结构保持一致&#xff09; 新建 public src 等文件夹npm init -y 创建package.json文件tsc --init…

【Ubuntu20.04安装java-8-openjdk】

1 下载 官网下载链接&#xff1a; https://www.oracle.com/java/technologies/downloads/#java8 下载 最后一行 jdk-8u411-linux-x64.tar.gz&#xff0c;并解压&#xff1a; tar -zxvf jdk-8u411-linux-x64.tar.gz2 环境配置 1、打开~/.bashrc文件 sudo gedit ~/.bashrc2、…

NGINX App Protect现已支持NGINX开源版 全方位加强现代应用安全防护

近日&#xff0c;F5 NGINX 发布全新升级的NGINX App Protect 5.0版本&#xff0c;将先前专属于NGINX 商业版本NGINX Plus 的现代应用安全能力拓展至NGINX开源版中&#xff0c;为增强现代应用和API安全防护提供全方位支持。此次升级后&#xff0c;适用于云端及本地部署的NGINX A…

C++:位图和布隆过滤器

一&#xff0c;位图 1.1 位图的概念 究竟什么是位图呢&#xff1f;&#xff1f;我们用一道问题来引入 问题&#xff1a;给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在 这40亿个数中。【腾讯】 根据这个问题&#x…

java——嵌套(二)

目录 一&#xff1a;方法的重写&#xff08;覆盖/覆写&#xff09; 1. 方法的重写的意义&#xff1a; 2. 重写&#xff08;overide&#xff09; 3. 案例 二&#xff1a;继承中构造方法的调用 1. 子类的构造方法会默认调用父类的构造方法&#xff1b; 2. super 关键字调用…

基于MPPT最大功率跟踪和SVPWM的光伏三相并网逆变器simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于MPPT最大功率跟踪和SVPWM的光伏三相并网逆变器simulink建模与仿真。包括PV模块&#xff0c;MPPT模块&#xff0c;SVPWM模块&#xff0c;电网模块等。 2.系统仿真结果 1不…

JavaScript异步编程——04-同源和跨域

同源和跨域 同源 同源策略是浏览器的一种安全策略&#xff0c;所谓同源是指&#xff0c;域名&#xff0c;协议&#xff0c;端口完全相同。 跨域问题的解决方案 从我自己的网站访问别人网站的内容&#xff0c;就叫跨域。 出于安全性考虑&#xff0c;浏览器不允许ajax跨域获取…

二总线,替代传统485总线通讯,主站设计

二总线通信设计专栏 《二总线&#xff0c;替代传统485总线通讯&#xff0c;选型及应用-CSDN博客》《二总线&#xff0c;替代传统485总线通讯&#xff0c;低成本直流载波方案实现及原理-CSDN博客》《二总线&#xff0c;替代传统485总线通讯&#xff0c;调试避坑指南之最大的电流…

基于控制工程的牛鞭效应simulink建模与仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 牛鞭效应”对供应链性能和绩效产生了严重的影响。基于控制理论建立了多级线性供应链的模型&#xff0c;分别利用噪声带宽和Matlab&#xff0f;Simulink对一个可扩…

【快捷部署】024_Hive(3.1.3)

&#x1f4e3;【快捷部署系列】024期信息 编号选型版本操作系统部署形式部署模式复检时间024Hive3.1.3Ubuntu 20.04tar包单机2024-05-07 一、快捷部署 #!/bin/bash ################################################################################# # 作者&#xff1a;cx…

竞赛 基于深度学习的人脸性别年龄识别 - 图像识别 opencv

文章目录 0 前言1 课题描述2 实现效果3 算法实现原理3.1 数据集3.2 深度学习识别算法3.3 特征提取主干网络3.4 总体实现流程 4 具体实现4.1 预训练数据格式4.2 部分实现代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…

CopyClip for Mac - 高效复制粘贴,轻松管理剪贴板

CopyClip for Mac&#xff0c;一款专为Mac用户打造的剪贴板管理工具&#xff0c;让你在复制粘贴的日常任务中&#xff0c;享受到前所未有的高效与便捷。 它常驻在菜单栏中&#xff0c;时刻准备为你服务。一旦你复制了内容&#xff0c;CopyClip就会自动将其保存至历史记录中&…

使用ffmpeg对视频进行转码(支持浏览器播放)

在开发中&#xff0c;算法保存的mp4视频文件通过路径打开该视频发现视频播放不了&#xff0c;需要转码进行播放。使用java代码进行转码。代码如下&#xff0c;inputFilePath是转之前的视频路径&#xff0c;outputFilePath是转之后的视频路径。ffmpeg命令中libx264也可以改为其它…

经验浅谈!伦敦银如何交易?

近期&#xff0c;伦敦银价格出现很强的上涨&#xff0c;这促使一些新手投资者进入了市场&#xff0c;但由于缺乏经验&#xff0c;他们不知道该怎么在市场中交易&#xff0c;下面我们就从宏观上介绍一些方法&#xff0c;来讨论一下伦敦银如何交易。 首先我们要知道&#xff0c;要…

vue3创建响应式数据ref和reactive的区别

reactive和ref在Vue.js中都是用于创建响应式数据的&#xff0c;但它们之间存在一些区别 定义数据类型不同。ref主要用于定义基本数据类型&#xff0c;如字符串、数字、布尔值等&#xff1b;reactive主要用于定义对象&#xff08;或数组&#xff09;类型的数据&#xff0c;但re…

【uniapp】阿里云OSS上传 [视频上传]

引用uniapp插件市场的插件,使用的是视频上传 &#xff08;阿里云 oss上传&#xff09; 我只使用了H5和App端&#xff0c;需要后端配置跨域 yk-authpup详情请参考 》》【用户告知权限申请的目的】 【插件市场】阿里云存储OSS前端直接上传(全端通用) - 前端JASON <template>…

scikit-learn多因子线性回归预测房价

1.首先是单因子线性回归预测房价 import numpy as np import pandas as pd from matplotlib import pyplot as plt from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, r2_score# 1.读取csa房屋数据 path D:/pythonDATA/us…

【前端学习——css模块化】

https://segmentfault.com/a/1190000039772466#item-2 CSS 命名方法论 为选择器增加冗长的前缀或后缀&#xff0c;手写命名前缀后缀的方式来生成全局唯一的命名 很麻烦不方便 CSS Modules 在外部管理 CSS&#xff0c;然后将类名映射到组件内部&#xff0c;他会为每个 class 都…

[C++]哈希应用-布隆过滤器快速入门

布隆过滤器 布隆过滤器&#xff08;Bloom Filter&#xff09;是一个由布隆在1970年提出的概率型数据结构&#xff0c;它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器的主要特点是高效的插入和查询&#xff0c;可以用于检索一个元素是否在一个集合中。 原理…