Google Test 学习笔记(简称GTest)
文章目录
- 一、介绍
- 1.1 介绍
- 1.2 教程
- 二、使用
- 2.1 基本使用
- 2.1.1 安装GTest (下载和编译)
- 2.1.2 编写测试
- 2.1.3 运行测试
- 2.1.4 高级特性
- 2.1.5 调试和分析
- 2.2 源码自带测试用例
- 2.3 TEST 使用
- 2.3.1 TestCase的介绍
- 2.3.2 TEST宏
- demo1
- demo2
- 2.3.3 TEST_F宏
- 2.3.4 TEST 和 TEST_IF 区别
- 2.4 EXPECT_*和ASSERT_*的宏介绍
- 2.4.1 gtest之断言
- 2.4.2 Boolean断言类型
- 2.4.3 二元值断言类型
- 2.4.4 字符串断言类型
- 三、参考资料
- 四、其他内容
- 4.1 gtest 和 C++ 版本
一、介绍
1.1 介绍
Google Test(通常简称GTest)是Google开发的一个用于C++的单元测试框架,它可以帮助你轻松地编写和运行测试用例,确保代码的质量和稳定性。
- 最大好处:实现自动化单元测试
1.2 教程
- 官网:https://google.github.io/googletest/
- 源码:https://github.com/google/googletest
- 参考:gtest教程(记录小白从0学习gtest的过程)
- GoogleTest测试框架介绍(二)
- C++ 的测试框架之使用 gtest 编写单元测试
二、使用
- 编译库
- 编写工程代码
- 编写测试用例代码
- 工程:
- 工程源码:库 / 程序
- samples:示例程序,演示如何使用库的基本功能。
- test:gtest
2.1 基本使用
2.1.1 安装GTest (下载和编译)
1.下载源码:
访问Google Test GitHub仓库,下载或克隆源码。
2.编译GTest:
GTest可以通过CMake等构建工具来构建。以CMake为例,你需要创建一个构建目录,然后运行CMake和Make工具。
mkdir build
cd build
cmake ..
make
3.安装GTest:
将GTest的库文件和头文件复制到你的项目中,或者在你的构建系统中链接GTest库。
2.1.2 编写测试
1.包含GTest头文件:
在你的测试文件中,需要包含GTest的头文件。
#include "gtest/gtest.h"
2.定义测试用例和测试函数:
测试用例(TEST_F)通常对应于一组相关的测试函数,而测试函数(TEST)则是具体执行的测试逻辑。
TEST(FactorialTest, PositiveNumbers) { // 单独的测试函数EXPECT_EQ(1, Factorial(0));EXPECT_EQ(1, Factorial(1));EXPECT_EQ(2, Factorial(2));EXPECT_EQ(6, Factorial(3));
}class MyMathTest : public ::testing::Test {
protected:void SetUp() override {// 初始化工作}
};TEST_F(MyMathTest, TestAddition) {EXPECT_EQ(5, Add(2, 3));
}
3.断言:
使用GTest提供的断言来检查函数的行为是否符合预期。例如,EXPECT_EQ用于比较两个值是否相等。
4.测试驱动:
在main函数中调用::testing::InitGoogleTest和RUN_ALL_TESTS来初始化GTest并运行所有的测试。
int main(int argc, char **argv) {::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}
2.1.3 运行测试
1.编译测试:
使用你的构建系统(如Makefile或CMakeLists.txt)来编译你的测试代码。
2.执行测试:
运行生成的可执行文件来执行测试。GTest会输出测试的结果,包括通过、失败或跳过的测试。
2.1.4 高级特性
- 参数化测试:使用INSTANTIATE_TEST_SUITE_P来创建一系列使用不同参数的测试用例。
- 死亡测试:使用ASSERT_DEATH或EXPECT_DEATH来检查代码是否会在特定条件下崩溃。
- Google Mock:GTest的一部分,用于创建和使用mock对象来进行更复杂的测试。
2.1.5 调试和分析
- 测试过滤:在运行测试时,可以使用–gtest_filter参数来指定运行哪些测试。
- 测试日志:使用–gtest_output=xml:test_results.xml等选项来生成测试报告。
2.2 源码自带测试用例
- 参考:https://gitcode.csdn.net/65acab6ab8e5f01e1e451947.html
我们还没有添加我们自己的源码,和针对源码的测试用例,但是谷歌已经写好了一些例子,可以先体验下,放在如下路径:/xxx/googletest-1.15.0/googletest
测试:
-
修改 CMakeLists.txt
# 这里 OFF 改成 ON option(gtest_build_samples "Build gtest's sample programs." OFF)
相关编译内容:
if (gtest_build_samples)cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc)cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc)cxx_executable(sample3_unittest samples gtest_main)cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc)cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc)cxx_executable(sample6_unittest samples gtest_main)cxx_executable(sample7_unittest samples gtest_main)cxx_executable(sample8_unittest samples gtest_main)cxx_executable(sample9_unittest samples gtest)cxx_executable(sample10_unittest samples gtest) endif()
-
编译:
mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=pwd/result -DGOOGLETEST_VERSION=1.5.0 .. make -j4# 单个文件编译 # g++ ../src/gtest_main.cc sample1.cc sample1_unittest.cc -o test -lgtest -lgmock -lpthread -std=c++11
-
运行:
./sample1_unittest
输出:
-
理解:
- gtest_main.cc :测试主程序入口,不是我们待测源码的主程序入口。
情况一:整个工程有两个main函数,一个是测试的main,一个可能是待测源码的main,两个包含main的文件不能同时编译,因为一个执行程序只能有一个入口。(可以n个文件n个main函数)
情况二:一个main函数通过宏定义区分启动 - sample1.cc:待测源码,就是测试对象,我们就是要对个源码进行白盒测试。
- sample1_unittest.cc:测试用例,里面就是我们针对源码写的测试用例脚本。
- gtest_main.cc :测试主程序入口,不是我们待测源码的主程序入口。
-
工程:
- 工程源码:库 / 程序
- samples:示例程序,演示如何使用库的基本功能。
- test:gtest
-
遗留问题:编译没看懂—>再看
2.3 TEST 使用
- 转自:Gtest入门2 Gtest之TEST宏的用法
2.3.1 TestCase的介绍
Gtest提供了若干个case方法进行测试不同的用例。主要常见的有TEST/TEST_F及TEST_P宏的使用。
在每个TestCase中可以通过断言提供的方法进行控制检查程序的预期走向是否是期望的结果,从而以此来判定程序的正确性。
在同一份TestCase中不能同时出现TEST和TEST_F两者进行混用;
其次TEST_F比TEST强的地方是会通过继承::testing::Test生成一个新类,而且这是必须的。
在新类中可以通过void SetUp();和void TearDown();进行创建和清除相关的资源数据;
2.3.2 TEST宏
TEST宏的作用是创建一个简单测试,它定义了一个测试函数,在这个函数里可以使用任何C++代码并使用提供的断言来进行检查。
TEST语法定义:
TEST(test_case_name, test_name)
- test_case_name第一个参数是测试用例名,通常是取测试函数名或者测试类名
- test_name 第二个参数是测试名这个随便取,但最好取有意义的名称
- 当测试完成后显示的测试结果将以"测试用例名.测试名"的形式给出
demo1
// test.cpp
// g++ -std=c++14 ../../src/gtest_main.cc test.cpp -o test -I../../include -L ../lib -lgtest -lpthread
#include <iostream>
#include <memory>
#include <gtest/gtest.h>using namespace std;class Base {
public:Base(std::string name):m_name{name} {std::cout << "name: " << m_name << std::endl;}std::string getName() {return m_name;}~Base() {std::cout << "destory base" << std::endl;}
private:std::string m_name;
};void getNameFunc(std::shared_ptr<Base> base) {std::cout << __func__ << " : usercount: " << base.use_count() << std::endl;std::cout << __func__ << " : name: " << base->getName() << std::endl;// EXPECT_EQ(2, base.use_count());
}TEST(Base, createInstance) {std::unique_ptr<Base> instance = make_unique<Base>("SvenBaseUnique");// 测试创建的instance实例是否不为nullptrEXPECT_NE(instance, nullptr);instance.reset();// 测试instance实例是否为nullptrEXPECT_EQ(instance, nullptr);
}TEST(Base, getName) {std::unique_ptr<Base> instance = make_unique<Base>("BaseUnique");EXPECT_NE(instance, nullptr);auto name = instance->getName();// 测试获取的name值是否和被给的值相等EXPECT_STREQ(name.c_str(), "BaseUnique");instance.reset();EXPECT_EQ(instance, nullptr);
}TEST(Base, shared_ptr) {std::shared_ptr<Base> instance = std::make_shared<Base>("BaseShared");EXPECT_NE(instance, nullptr);std::cout << "shared_ptr.use_count: " << instance.use_count() << std::endl;// 测试instance引用次数是否为1EXPECT_EQ(1, instance.use_count());getNameFunc(instance);EXPECT_EQ(1, instance.use_count());
}TEST(Base, unique_ptr) {std::unique_ptr<Base> instance = make_unique<Base>("BaseUnique");EXPECT_NE(instance, nullptr);getNameFunc(std::move(instance));EXPECT_EQ(instance, nullptr);
}
demo2
// test_2.cc
// g++ -std=c++14 test_2.cc -o test_2 -I../../include -L ../lib -lgtest -lpthread
#include <gtest/gtest.h>
#include <vector>
#include <string>
#include <cmath>// 示例函数,用于测试
int Add(int a, int b) {return a + b;
}std::vector<int> GetPrimesUnder100() {std::vector<int> primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};return primes;
}class StringClass {
public:std::string Reverse(const std::string& s) {return std::string(s.rbegin(), s.rend());}
};// 测试类
class MyTest : public ::testing::Test {
protected:StringClass stringObj;
};// 测试用例:测试 Add 函数
TEST(AdditionTest, HandlesZeroInput) {EXPECT_EQ(Add(0, 0), 0);ASSERT_EQ(Add(0, 1), 1);// EXPECT_EQ(Add(0, 0), 30); // error test// ASSERT_EQ(Add(0, 1), 30);// ASSERT_EQ(Add(1, 1), 2);
}TEST(AdditionTest, HandlesPositiveInput) {EXPECT_EQ(Add(2, 3), 5);ASSERT_EQ(Add(-1, 1), 0);
}TEST(AdditionTest, HandlesNegativeInput) {EXPECT_EQ(Add(-1, -1), -2);ASSERT_EQ(Add(-2, 3), 1);
}// 测试用例:测试 GetPrimesUnder100 函数
TEST(PrimeTest, ReturnsCorrectPrimes) {auto primes = GetPrimesUnder100();ASSERT_EQ(primes.size(), 25);EXPECT_EQ(primes[0], 2);EXPECT_EQ(primes[24], 97);
}// 测试用例:测试 StringClass 的 Reverse 方法
TEST_F(MyTest, ReversesString) {std::string original = "hello";std::string reversed = stringObj.Reverse(original);EXPECT_EQ(reversed, "olleh");
}TEST_F(MyTest, ReversesEmptyString) {std::string original = "";std::string reversed = stringObj.Reverse(original);EXPECT_EQ(reversed, "");
}TEST_F(MyTest, ReversesSingleCharacterString) {std::string original = "a";std::string reversed = stringObj.Reverse(original);EXPECT_EQ(reversed, "a");
}// 测试用例:测试浮点数比较
TEST(FloatTest, ComparesFloats) {float a = 1.0f + 1e-5f;float b = 1.0f;EXPECT_NEAR(a, b, 1e-4f);
}// 测试用例:测试布尔值
TEST(BooleanTest, ChecksTrue) {bool condition = true;EXPECT_TRUE(condition);ASSERT_TRUE(condition);
}TEST(BooleanTest, ChecksFalse) {bool condition = false;EXPECT_FALSE(condition);ASSERT_FALSE(condition);
}// 测试用例:测试异常
TEST(ExceptionTest, ThrowsException) {ASSERT_THROW(throw std::runtime_error("test exception"), std::runtime_error);
}// 测试用例:测试子测试
TEST(SubtestTest, Subtest1) {SUCCEED() << "This is a subtest.";EXPECT_EQ(1, 1);
}TEST(SubtestTest, Subtest2) {SUCCEED() << "This is another subtest.";EXPECT_EQ(2, 2);
}int main(int argc, char **argv) {::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}
2.3.3 TEST_F宏
TEST_F主要是进行多样测试,就是多种不同情况的测试TestCase中都会使用相同一份的测试数据的时候将会才用它。
即用相同的数据测试不同的行为,如果采用TEST宏进行测试那么将会为不同的测试case创建一份数据。TEST_F宏将会共用一份避免重复拷贝共具灵活性。
语法定义为:
TEST_F(test_case_name, test_name);
- test_case_name第一个参数是测试用例名,必须取类名。这个和TEST宏不同
- test_name 第二个参数是测试名这个随便取,但最好取有意义的名称
- 使用TEST_F时必须继承::testing::Test类。并且该类提供了两个接口void SetUp(); void TearDown();
void SetUp()函数,为测试准备对象. void TearDown()函数 为测试后销毁对象资源
2.3.4 TEST 和 TEST_IF 区别
在 Google Test 中,TEST
和 TEST_F
是用来定义测试用例的两个不同的宏。它们之间的主要区别在于是否需要测试夹具(test fixture):
-
TEST(SuiteName, TestName)
TEST
宏用于定义不需要特殊初始化或清理的简单测试用例。- 它不接受任何参数,因此也不需要测试夹具类。
- 测试用例函数是自动实例化的,并且每个测试用例都是独立的,不共享任何设置。
- 适用于快速、独立的测试,不需要重复的初始化逻辑。
示例代码:
TEST(MultiplicationTest, HandlesZero) {EXPECT_EQ(0 * 5, 0); }
-
TEST_F(TestFixture, TestName)
TEST_F
宏用于定义需要使用测试夹具的测试用例。- 测试夹具是一个从
::testing::Test
派生的类,你可以在里面定义公共和受保护的成员,这些成员在每个测试用例中都可以访问。 - 测试夹具类允许你在
SetUp
方法中编写初始化代码,这些代码会在每个测试用例运行之前执行,而在TearDown
方法中编写清理代码,这些代码会在每个测试用例运行之后执行。 - 适用于需要共享初始化逻辑和成员数据的测试用例。
示例代码:
class MultiplicationTest : public ::testing::Test { protected:int result;void SetUp() override {result = 0;}void TearDown() override {// 清理工作,如果需要的话} };TEST_F(MultiplicationTest, HandlesZero) {result = 0 * 5;EXPECT_EQ(result, 0); }
除了 TEST
和 TEST_F
,Google Test 还有一个宏 TEST_P
,它用于定义参数化测试。参数化测试允许你用不同的参数多次运行同一个测试用例。
关于 TEST_IF
宏,实际上 Google Test 标准库中并没有这个宏。可能你指的是 TEST_P
或者某个特定版本的 Google Test 中的宏,或者是第三方扩展。通常情况下,TEST_P
用于参数化测试,允许你为测试用例提供参数,并且可以结合 INSTANTIATE_TEST_CASE_P
宏来实例化多个测试用例。
如果你需要更具体的信息或者有特定的使用场景,请提供更多的上下文,我可以给出更准确的答案。
2.4 EXPECT_*和ASSERT_*的宏介绍
- 转自:Gtest入门2 Gtest之TEST宏的用法
2.4.1 gtest之断言
要测试一个类或函数,我们需要对其行为做出断言。当一个断言失败时,Google Test会在屏幕上输出该代码所在的源文件及其所在的位置行号,以及错误信息。也可以在编写断言时,提供一个自定义的错误信息,这个信息在失败时会被附加在Google Test的错误信息之后。
断言常常成对出现,它们都测试同一个类或者函数,但对当前功能有着不同的效果。
- ASSERT_*版本的断言失败时会产生致命失败,并结束当前函数。
- EXPECT_*版本的断言产生非致命失败,而不会中止当前函数。
通常更推荐使用EXPECT_*断言,因为它们运行一个测试中可以有不止一个的错误被报告出来。但如果在编写断言如果失败,就没有必要继续往下执行的测试时,你应该使用ASSERT_*断言。 因为失败的ASSERT_*断言会立刻从当前的函数返回,可能会跳过其后的一些的清洁代码,这样也许会导致空间泄漏。
gtest中断言的宏可以分为两类:一类是ASSERT宏,另一类就是EXPECT宏了。
1、ASSERT_*系列:如果当前点检测失败则退出当前函数
2、EXPECT_*系列:如果当前点检测失败则继续往下执行
2.4.2 Boolean断言类型
2.4.3 二元值断言类型
比较两个值的大小。
2.4.4 字符串断言类型
比较两个字符串。
三、参考资料
-
玩转C++单元测试之快速上手gtest
-
Google Test(GTEST)使用入门(1)- 下载编译安装执行
四、其他内容
4.1 gtest 和 C++ 版本
Google Test(GTest)对不同版本的 C++ 标准的支持有所变化。下面是 Google Test 对 C++ 标准版本支持的大致时间线和相关信息。
Google Test 对 C++ 标准的支持
-
GTest 1.8.1(发布于 2015 年 7 月 29 日):
- 支持 C++98、C++03、C++11、C++14。
- 从 GTest 1.8.1 开始,GTest 支持 C++14,并且开始逐渐移除对旧版本 C++ 标准的支持。
-
GTest 1.10.0(发布于 2019 年 10 月 28 日):
- 支持 C++11、C++14、C++17。
- GTest 1.10.0 版本开始正式移除对 C++98 和 C++03 的支持。
-
GTest 1.11.0(发布于 2021 年 1 月 25 日):
- 支持 C++11、C++14、C++17。
- GTest 1.11.0 版本继续支持 C++11、C++14 和 C++17。
-
GTest 1.12.1(发布于 2022 年 8 月 17 日):
- 支持 C++11、C++14、C++17、C++20。
- GTest 1.12.1 版本增加了对 C++20 的支持。
-
GTest 1.13.0(发布于 2023 年 11 月 2 日):
- 支持 C++14、C++17、C++20。
- GTest 1.13.0 版本移除了对 C++11 的支持,现在仅支持 C++14 及以上版本。
总结
-
最新版本(截至 2024 年 7 月 25 日):
- GTest 1.13.0 支持 C++14、C++17 和 C++20。
-
历史版本:
- GTest 1.12.1 支持 C++11、C++14、C++17 和 C++20。
- GTest 1.11.0 支持 C++11、C++14 和 C++17。
- GTest 1.10.0 支持 C++11、C++14 和 C++17。
- GTest 1.8.1 支持 C++98、C++03、C++11 和 C++14。
建议
-
使用最新版本:
- 如果您的项目可以使用较新的 C++ 版本,建议使用 GTest 1.13.0 或更高版本,以获得更好的特性和支持。
- 对于 C++14 及以上版本的支持,您可以使用 GTest 1.13.0。
-
使用较旧版本:
- 如果您的项目受限于旧版本的 C++,您可以考虑使用相应的 GTest 版本。例如,如果您的项目使用 C++11,您可以考虑使用 GTest 1.12.1 或更低版本。
示例编译命令
如果您使用的是 GTest 1.13.0 或更高版本,并且您的编译器支持 C++14 或更高版本,您可以使用以下编译命令:
g++ -std=c++14 ../../src/gtest_main.cc test.cpp -o test -I../../include -L ../lib -lgtest -lpthread
请确保您的编译器支持所需的 C++ 标准版本。如果您的编译器不支持 C++14 或更高版本,您可能需要升级编译器或考虑使用较低版本的 GTest。
如果您需要使用 C++11,您可以使用 GTest 1.12.1 或更低版本,并相应地更新编译命令中的 C++ 标准版本:
g++ -std=c++11 ../../src/gtest_main.cc test.cpp -o test -I../../include -L ../lib -lgtest -lpthread
请根据您的具体需求调整编译命令中的 C++ 标准版本。
相关文章:
Google Test 学习笔记(简称GTest)
文章目录 一、介绍1.1 介绍1.2 教程 二、使用2.1 基本使用2.1.1 安装GTest (下载和编译)2.1.2 编写测试2.1.3 运行测试2.1.4 高级特性2.1.5 调试和分析 2.2 源码自带测试用例2.3 TEST 使用2.3.1 TestCase的介绍2.3.2 TEST宏demo1demo2 2.3.3 TEST_F宏2.3…...
不可变集合
定义:就是集合中的内容不可以被修改。 如何获取不可变集合? List、Set、Map类中提供的静态方法of可用来获取不可变集合。 特点:一旦创建完成只可以进行查询,不可以增删改。 细节:Map集合中的of方法只能添加10个键值…...
景区AR导航营销系统:技术解决方案与实施效益分析
随着旅游市场的竞争日益激烈,景区需要不断创新以吸引游客。景区 AR 导航将虚拟画面与现实场景相结合,为游客提供了更加直观、生动的导航服务。对于景区而言,这一创新技术无疑是吸引游客目光、提升景区知名度的有力武器。通过独特的 AR 导航体…...
MATLAB的基础知识
matlab的基本小常识 1. 在每行语句后面加上英文分号表示不在命令行窗口显示运行结果。 a 3; a 5 2. 多行注释快捷键,CTRLR。 3. 取消多行注释,CTRLT。 4. 清空工作区的所有变量使用clear。 5. 清空命令行窗口的所有变量使用clc。 6. clc和clear一起使…...
Redis-高级实战案例
文章目录 Redis集群崩溃时如何保证秒杀系统高可用1. 冗余与备份2. 故障检测与自动切换3. 降级策略4. 数据一致性5. 客户端缓存6. 异常处理与通知7. 测试与演练8. 服务降级与回滚Redis主从切换导致库存同步异常以及超卖问题主从切换导致的库存同步异常原因:解决方案:秒杀链路中…...
d3d12.dll 文件缺失如何解决?五种修复丢失问题的方法
d3d12.dll 文件缺失如何解决?它为什么会不见呢?今天,我们将探讨 d3d12.dll 文件的重要性、原因以及丢失时的解决策略。本文将全面介绍 d3d12.dll 文件,并提供五种修复丢失问题的方法。 d3d12.dll文件是什么的详细介绍 d3d12.dll …...
Linux下如何设置系统定时任务
在Linux系统中,用户可以使用cron工具来设置定时任务。cron是一个守护进程,用于在指定的时间间隔执行指定的命令或脚本。下面是在Linux系统中设置系统定时任务的步骤。 使用crontab命令编辑定时任务列表: crontab -e该命令会打开一个文本编辑…...
【React】JSX 实现列表渲染
文章目录 一、基础语法1. 使用 map() 方法2. key 属性的使用 二、常见错误和注意事项1. 忘记使用 key 属性2. key 属性的选择 三、列表渲染的高级用法1. 渲染嵌套列表2. 条件渲染列表项3. 动态生成组件 四、最佳实践 在 React 开发中,列表渲染是一个非常常见的需求。…...
写一个简单的兼容GET/POST请求的登录接口
本文目录 安装JDK17安装或者更新Intelij Idea 2024SpringBoot生成项目压缩包下载maven,idea添加maven写POST接口浏览器访问GET接口PostMan安装及访问POST接口 安装JDK17 参考:https://blog.csdn.net/tiehou/article/details/129575138 安装或者更新Int…...
【好玩的经典游戏】Docker环境下部署赛车小游戏
【好玩的经典游戏】Docker环境下部署赛车小游戏 一、小游戏介绍1.1 小游戏简介1.2 项目预览二、本次实践介绍2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 安装Docker环境3.2 检查Docker服务状态3.3 检查Docker版本3.4 检查docker compose 版本四、构建容器镜像4.1 下…...
物理机 gogs+jenkins+sonarqube 实现CI/CD
一、部署gogs_0.11.91_linux_amd64.tar.gz gogs官网下载:https://dl.gogs.io/ yum -y install mariadb-serversystemctl start mariadbsystemctl enable mariadbuseradd gittar zxvf gogs_0.11.91_linux_amd64.tar.gzcd gogsmysql -u root -p < scripts/mysql.…...
前端表格解析方法
工具类文件 // fileUtils.tsimport { ref } from vue; import * as xlsx from xlsx;interface RowData {[key: string]: any; }export const tableData ref<RowData[]>([]);export async function handleFileSelect(url: string): Promise<void> {try {const res…...
Leetcode 3227. Vowels Game in a String
Leetcode 3227. Vowels Game in a String 1. 解题思路2. 代码实现 题目链接:3227. Vowels Game in a String 1. 解题思路 这一题稍微分析一下之后就会发现,这个游戏有且只有一种情况Bob才能够赢,即原始字符串当中不存在元音字母的情况&…...
树莓派4B从装系统raspbian到vscode远程编程(python)
1、写在前面 前面用的一直是Ubuntu系统,但是遇到一个奇葩的问题: 北通手柄在终端可以正常使用,接收到数据 但在python程序中使用pygame库初始化时总是报错:Invalid device number,检测不到手柄 经过n次重装系统&am…...
vue上传Excel文件并直接点击文件列表进行预览
本文主要内容:用elementui的Upload 组件上传Excel文件,上传后的列表采用xlsx插件实现点击预览表格内容效果。 在项目中可能会有这样的需求,有很多种方法实现。但是不想要跳转外部地址,所以用了xlsx插件来解析表格,并展…...
OpenCV 像素操作—证件照换底色详细原理 C++纯手写实现
文章目录 总体步骤1.RGB转HSV2.找出要换的底色3.取反,黑白颠倒4.将原图像的非背景部分复制到新背景上 完整代码1.C纯手写版2.官方API版本 总体步骤 1.RGB转HSV 为什么一定要转为HSV 颜色空间? 将图像从BGR颜色空间转换为HSV颜色空间是因为HSV颜色空间更…...
tinygrad框架简介;MLX框架简介
目录 tinygrad框架简介 MLX框架简介 LLaMA编辑 Stable Diffusion编辑 tinygrad框架简介 极简主义与易扩展性 tinygrad 的设计理念是极简主义。与 XLA 类比,如果 XLA 是复杂指令集计算 (CISC),那么 tinygrad 就是精简指令集计算 (RISC)。这种简约的设计使得它成为添加…...
服务器重启了之后就卡在某个页面了,花屏,如何解决??
🏆本文收录于《CSDN问答解惑-专业版》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收…...
Hospital 14.6.0全开源医院管理预约系统源码
InfyHMS 具有 60 种功能和 9 种不同类型的用户类型, 他们可以登录系统并根据他们的角色访问他们的数据。 源码下载:https://download.csdn.net/download/m0_66047725/89580674 更多资源下载:关注我。...
C/C++樱花树代码
目录 写在前面 系列文章 C简介 完整代码 代码分析 写在后面 写在前面 C实现精美的樱花树,只需这100行代码! 系列文章 序号目录直达链接1爱心代码https://want595.blog.csdn.net/article/details/1363606842李峋同款跳动的爱心https://want595.b…...
sklearn基础学习
1. 简介 1.1 什么是sklearn sklearn,或者更正式地称为scikit-learn,是一个基于Python的开源机器学习库。它建立在NumPy、SciPy和matplotlib之上,提供了简单而有效的工具用于数据挖掘和数据分析。sklearn支持监督学习和无监督学习算法&#…...
SpringBoot 自动配置原理
一、Condition Condition 是在 Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean 操 作。 思考: SpringBoot 是如何知道要创建哪个 Bean 的?比如 SpringBoot 是如何知道要创建 RedisTemplate 的? …...
Redisson中RQueue的使用场景附一个异步的例子
RQueue 是一个基于 Redis 的分布式作业队列系统,它允许开发者在 Ruby 应用程序中实现异步任务处理和计划任务调度。由于 Redis 提供了高性能的内存数据结构存储,RQueue 可以快速地存储和检索队列中的任务,这使得它非常适合于高并发和低延迟的…...
SpringMVC 控制层框架-下
五、SpringMVC其他扩展 1. 异常处理机制 1.1 异常处理概念 开发过程中是不可避免地会出现各种异常情况,例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题,甚至直接导致程序崩溃。因此,在开发过程中&a…...
(四)js前端开发中设计模式之工厂方法模式
工厂方法模式,通过对产品类的抽象,使其创建业务主要用于负责创建多类产品的实例 const Java function (content) {this.content content;(function () {let oDiv document.createElement(div)oDiv.innerHTML contentoDiv.style.color greendocument.getElement…...
新版GPT-4omini上线!快!真TM快!
大半夜,OpenAI突然推出了GPT-4o mini版本。 当我看到这条消息时,正准备去睡觉。mini版本质上是GPT-4o模型的精简版本,没有什么革命性的创新,因此我并没有太在意。 结果今天早上一觉醒来发现伴随GPT-4o mini上线,官网和…...
【Unity】RPG2D龙城纷争(十七)敌方常规AI(Normal)的实现
更新日期:2024年7月24日。 项目源码:第五章发布(正式开始游戏逻辑的章节) 索引 简介一、AI_Normal类二、AI调遣策略第一阶段:收集1.提供战场数据收集方法2.收集战场数据三、AI调遣策略第二阶段:评估四、AI调遣策略第三阶段:行动简介 AI_Normal定位为框架自带的最基础的…...
Tracy 小笔记:微信小程序 mpx 雷达图的实现
使用文档: https://www.kancloud.cn/xchhhh/wx-chart/399337 https://github.com/xiaolin3303/wx-charts https://gitee.com/mirrors/wx-charts/#wx-charts 参数说明: https://github.com/xiaolin3303/wx-charts/issues/56 下载 dist 里的 wx-charts-…...
Unity UGUI 之 Input Field
本文仅作学习笔记与交流,不作任何商业用途 本文包括但不限于unity官方手册,唐老狮,麦扣教程知识,引用会标记,如有不足还请斧正 1.Input Field是什么? 给玩家提供输入的输入框 2.重要参数 中英文对照着看…...
SpringBoot接入mongodb例子,并有增删改查功能
1,首先,在pom.xml中添加依赖: <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency><!--上面这…...
类和对象(三)
目录 一. 构造函数初始化列表 二. 类型转换 三. static成员 四. 友元 五. 内部类 六. 匿名对象 七. 对象拷贝时的编译器优化 一. 构造函数初始化列表 1. 之前我们实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式&…...
Android SurfaceFlinger——GraphicBuffer初始化(二十九)
在 SurfaceFlinger 中,GraphicBuffer 是一个关键的数据结构,用于封装和管理图形数据的内存缓冲区。它不仅在 SurfaceFlinger 内部使用,也被其他组件如 GPU 驱动、摄像头服务、视频解码器等广泛利用,以实现高效的数据交换和图形渲染。 一、概述 GraphicBuffer 对象封装了一…...
pytest:4种方法实现 - 重复执行用例 - 展示迭代次数
简介:在软件测试中,我们经常需要重复执行测试用例,以确保代码的稳定性和可靠性。在本文中,我们将介绍四种方法来实现重复执行测试用例,并显示当前迭代次数和剩余执行次数。这些方法将帮助你更好地追踪测试执行过程&…...
一文入门SpringSecurity 5
目录 提示 Apache Shiro和Spring Security 认证和授权 RBAC Demo 环境 Controller 引入Spring Security 初探Security原理 认证授权图示编辑 图中涉及的类和接口 流程总结 提示 Spring Security源码的接口名和方法名都很长,看源码的时候要见名知意&am…...
IPython的HTML魔法:%%html_header命令全解析
IPython的HTML魔法:%%html_header命令全解析 在IPython和Jupyter Notebook中,%%html_header是一个魔术命令,它允许用户在Notebook的单元格中添加HTML头部(head)内容。这个功能特别有用,当你需要定制Notebo…...
将SQL中的占位符替换成参数
将SQL中的占位符替换成参数 描述 描述 此方法是将SQL中的${}或#{}替换为直接拼接到SQL中或直接替换为?的形式。具体详情看下面代码。 import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern;/*** author HuYu* date 2023-09-21* since 1.0**…...
锁相环 vivado FPGA
原理 同步状态/跟踪状态:相位差在2kπ附近,频率差为0到达上述状态的过程称为捕获过程锁相环的捕获带:delta w的最大值,大于这个值的话就不能捕获鉴相器(PD-phase discriminator):相乘加LPF&…...
英语科技写作 希拉里·格拉斯曼-蒂(英文版)pdf下载
下载链接: 链接1:https://pan.baidu.com 链接2:/s/1fxRUGnlJrKEzQVF6k1GmBA 提取码:b69t 由于是英文版,可能有些看着不太方便,可以在网页版使用以下软件中英文对照着看,看着更舒服,…...
《Dynamic Statistical Learning in Massive Datastreams》论文阅读笔记
论文地址: https://www3.stat.sinica.edu.tw/ss_newpaper/SS-2023-0195_na.pdf 论文题目翻译:《在大规模数据流中的动态统计学习》 核心观点: 动态跟踪和筛选框架(DTS):论文提出了一个在线学习和模型更新的新框架&…...
【数据分享】2008-2022年我国省市县三级的逐日NO2数据(excel\shp格式)
空气质量数据是在我们日常研究中经常使用的数据!之前我们给大家分享了2000-2022年的省市县三级的逐日PM2.5数据、2013-2022年的省市县三级的逐日CO数据和2013-2022年的省市县三级的逐日SO2数据(均可查看之前的文章获悉详情)! 本次…...
JavaEE (1)
web开发概述 所谓web开发,指的是从网页中向后端程序发送请求,与后端程序进行 交互. 流程图如下 Web服务器是指驻留于因特网上某种类型计算机的程序. 可以向浏览器等Web客户端提供文档,也可以放置网站文件,让全世界浏览; 它是一个容器&…...
事务、函数和索引
什么是事务? 事务(Transaction),就是将一组SQL语句放在同一批次内去执行,如果一个SQL语句出错,则该批次内 的所有SQL都将被取消执行。 特点 一个事务中如果有一个数据库操作失败,那么整个事务…...
Android APP 基于RecyclerView框架工程(知识体系积累)
说明:这个简单的基于RecyclerView的框架作用在于自己可以将平时积累的一些有效demo整合起来(比如音视频编解码的、opengles的以及其他也去方向的、随着项目增多,工程量的增加,后期想高效的分析和查找并不容易)…...
【iOS】GCD
参考文章:GCD函数和队列原理探索 之前写项目的时候,进行耗时的网络请求使用GCD处理过异步请求,但对一些概念都很模糊,这次就来系统学习一下GCD相关 相关概念 什么是GCD? Grand Center Dispatch简称GCD,是…...
C语言 | Leetcode C语言题解之第282题给表达式添加运算符
题目: 题解: #define MAX_COUNT 10000 // 解的个数足够大 #define NUM_COUNT 100 // 操作数的个数足够大 long long num[NUM_COUNT] {0};long long calc(char *a) { // 计算表达式a的值// 将数字和符号,入栈memset(num, 0, sizeof(num));in…...
如何使用 API list 极狐GitLab 容器镜像仓库中的 tag?
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署…...
粒子群算法PSO优化BP神经网络(PSO-BP)回归预测——Python和MATLAB实现
下面是一个使用Python实现的粒子群算法(PSO)优化反向传播神经网络(BP)的示例代码。 以下是具体的代码实现: python import numpy as np from sklearn.datasets import make_regression from sklearn.model_selection…...
React-router路由配置及跳转
1、V6对比V5的修改内容 1、API: useNavigate 代替了useHistory 。 2、废弃了Route组件的exact属性。 3、组件 <Routes>代替了<Switch> 4、组件NavLink中移除了 activeStyle activeClassName 属性。 2、安装依赖react-router-dom npm install react-router-dom…...
vue3【实战】可编辑的脱敏信息
<script lang"ts" setup> import { ref, onMounted } from "vue"; let real_name ref("朝阳");let name ref("");onMounted(() > {name.value des_name(real_name.value); });function focusing() {name.value real_name…...
S71200 - 笔记
1 S71200 0 ProfiNet - 2 PLC编程 01.如何零基础快速上手S7-1200_哔哩哔哩_bilibili 西门子S7-1200PLC编程设计学习视频,从入门开始讲解_哔哩哔哩_bilibili...