唐山做企业网站公司,cps推广联盟,什么网站可以做推广的,养老网站建设方案文章目录 一、介绍1.1 介绍1.2 教程 二、使用2.1 基本使用2.1.1 安装GTest #xff08;下载和编译#xff09;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… 文章目录 一、介绍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.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示例程序演示如何使用库的基本功能。testgtest
2.1 基本使用
2.1.1 安装GTest 下载和编译
1.下载源码 访问Google Test GitHub仓库下载或克隆源码。
2.编译GTest GTest可以通过CMake等构建工具来构建。以CMake为例你需要创建一个构建目录然后运行CMake和Make工具。
mkdir build
cd build
cmake ..
make3.安装GTest 将GTest的库文件和头文件复制到你的项目中或者在你的构建系统中链接GTest库。
2.1.2 编写测试
1.包含GTest头文件 在你的测试文件中需要包含GTest的头文件。
#include gtest/gtest.h2.定义测试用例和测试函数 测试用例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 MockGTest的一部分用于创建和使用mock对象来进行更复杂的测试。
2.1.5 调试和分析
测试过滤在运行测试时可以使用–gtest_filter参数来指定运行哪些测试。测试日志使用–gtest_outputxml: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 gtests 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_PREFIXpwd/result -DGOOGLETEST_VERSION1.5.0 ..
make -j4# 单个文件编译
# g ../src/gtest_main.cc sample1.cc sample1_unittest.cc -o test -lgtest -lgmock -lpthread -stdc11运行 ./sample1_unittest 输出 理解 gtest_main.cc 测试主程序入口不是我们待测源码的主程序入口。 情况一整个工程有两个main函数一个是测试的main,一个可能是待测源码的main两个包含main的文件不能同时编译因为一个执行程序只能有一个入口。可以n个文件n个main函数 情况二一个main函数通过宏定义区分启动 sample1.cc待测源码就是测试对象我们就是要对个源码进行白盒测试。sample1_unittest.cc测试用例里面就是我们针对源码写的测试用例脚本。 工程 工程源码库 / 程序samples示例程序演示如何使用库的基本功能。testgtest 遗留问题编译没看懂—再看
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 -stdc14 ../../src/gtest_main.cc test.cpp -o test -I../../include -L ../lib -lgtest -lpthread
#include iostream
#include memory
#include gtest/gtest.husing 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_ptrBase 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_ptrBase instance make_uniqueBase(SvenBaseUnique);// 测试创建的instance实例是否不为nullptrEXPECT_NE(instance, nullptr);instance.reset();// 测试instance实例是否为nullptrEXPECT_EQ(instance, nullptr);
}TEST(Base, getName) {std::unique_ptrBase instance make_uniqueBase(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_ptrBase instance std::make_sharedBase(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_ptrBase instance make_uniqueBase(BaseUnique);EXPECT_NE(instance, nullptr);getNameFunc(std::move(instance));EXPECT_EQ(instance, nullptr);
}demo2
// test_2.cc
// g -stdc14 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::vectorint GetPrimesUnder100() {std::vectorint 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_FGoogle 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 TestGTest对不同版本的 C 标准的支持有所变化。下面是 Google Test 对 C 标准版本支持的大致时间线和相关信息。
Google Test 对 C 标准的支持 GTest 1.8.1发布于 2015 年 7 月 29 日 支持 C98、C03、C11、C14。从 GTest 1.8.1 开始GTest 支持 C14并且开始逐渐移除对旧版本 C 标准的支持。 GTest 1.10.0发布于 2019 年 10 月 28 日 支持 C11、C14、C17。GTest 1.10.0 版本开始正式移除对 C98 和 C03 的支持。 GTest 1.11.0发布于 2021 年 1 月 25 日 支持 C11、C14、C17。GTest 1.11.0 版本继续支持 C11、C14 和 C17。 GTest 1.12.1发布于 2022 年 8 月 17 日 支持 C11、C14、C17、C20。GTest 1.12.1 版本增加了对 C20 的支持。 GTest 1.13.0发布于 2023 年 11 月 2 日 支持 C14、C17、C20。GTest 1.13.0 版本移除了对 C11 的支持现在仅支持 C14 及以上版本。
总结 最新版本截至 2024 年 7 月 25 日 GTest 1.13.0 支持 C14、C17 和 C20。 历史版本 GTest 1.12.1 支持 C11、C14、C17 和 C20。GTest 1.11.0 支持 C11、C14 和 C17。GTest 1.10.0 支持 C11、C14 和 C17。GTest 1.8.1 支持 C98、C03、C11 和 C14。
建议 使用最新版本 如果您的项目可以使用较新的 C 版本建议使用 GTest 1.13.0 或更高版本以获得更好的特性和支持。对于 C14 及以上版本的支持您可以使用 GTest 1.13.0。 使用较旧版本 如果您的项目受限于旧版本的 C您可以考虑使用相应的 GTest 版本。例如如果您的项目使用 C11您可以考虑使用 GTest 1.12.1 或更低版本。
示例编译命令
如果您使用的是 GTest 1.13.0 或更高版本并且您的编译器支持 C14 或更高版本您可以使用以下编译命令
g -stdc14 ../../src/gtest_main.cc test.cpp -o test -I../../include -L ../lib -lgtest -lpthread请确保您的编译器支持所需的 C 标准版本。如果您的编译器不支持 C14 或更高版本您可能需要升级编译器或考虑使用较低版本的 GTest。
如果您需要使用 C11您可以使用 GTest 1.12.1 或更低版本并相应地更新编译命令中的 C 标准版本
g -stdc11 ../../src/gtest_main.cc test.cpp -o test -I../../include -L ../lib -lgtest -lpthread请根据您的具体需求调整编译命令中的 C 标准版本。 文章转载自: http://www.morning.rfmzc.cn.gov.cn.rfmzc.cn http://www.morning.bby45.cn.gov.cn.bby45.cn http://www.morning.ryjl.cn.gov.cn.ryjl.cn http://www.morning.qygfb.cn.gov.cn.qygfb.cn http://www.morning.muzishu.com.gov.cn.muzishu.com http://www.morning.xylxm.cn.gov.cn.xylxm.cn http://www.morning.tjwfk.cn.gov.cn.tjwfk.cn http://www.morning.lmzpk.cn.gov.cn.lmzpk.cn http://www.morning.wmsgt.cn.gov.cn.wmsgt.cn http://www.morning.cfpq.cn.gov.cn.cfpq.cn http://www.morning.fksdd.cn.gov.cn.fksdd.cn http://www.morning.ailvturv.com.gov.cn.ailvturv.com http://www.morning.rfzzw.com.gov.cn.rfzzw.com http://www.morning.trbxt.cn.gov.cn.trbxt.cn http://www.morning.pqcsx.cn.gov.cn.pqcsx.cn http://www.morning.ktrzt.cn.gov.cn.ktrzt.cn http://www.morning.fylqz.cn.gov.cn.fylqz.cn http://www.morning.lmcrc.cn.gov.cn.lmcrc.cn http://www.morning.krhkb.cn.gov.cn.krhkb.cn http://www.morning.bcngs.cn.gov.cn.bcngs.cn http://www.morning.qmnhw.cn.gov.cn.qmnhw.cn http://www.morning.trtdg.cn.gov.cn.trtdg.cn http://www.morning.fbjqq.cn.gov.cn.fbjqq.cn http://www.morning.bnbzd.cn.gov.cn.bnbzd.cn http://www.morning.lkjzz.cn.gov.cn.lkjzz.cn http://www.morning.lmqw.cn.gov.cn.lmqw.cn http://www.morning.tnzwm.cn.gov.cn.tnzwm.cn http://www.morning.sfdky.cn.gov.cn.sfdky.cn http://www.morning.lzbut.cn.gov.cn.lzbut.cn http://www.morning.snmth.cn.gov.cn.snmth.cn http://www.morning.kyjpg.cn.gov.cn.kyjpg.cn http://www.morning.bxbkq.cn.gov.cn.bxbkq.cn http://www.morning.krlsz.cn.gov.cn.krlsz.cn http://www.morning.twwzk.cn.gov.cn.twwzk.cn http://www.morning.kxqwg.cn.gov.cn.kxqwg.cn http://www.morning.ktdqu.cn.gov.cn.ktdqu.cn http://www.morning.rjrh.cn.gov.cn.rjrh.cn http://www.morning.ggtgl.cn.gov.cn.ggtgl.cn http://www.morning.mrfjr.cn.gov.cn.mrfjr.cn http://www.morning.qwgct.cn.gov.cn.qwgct.cn http://www.morning.qyhcg.cn.gov.cn.qyhcg.cn http://www.morning.jzfxk.cn.gov.cn.jzfxk.cn http://www.morning.rltw.cn.gov.cn.rltw.cn http://www.morning.hmqmm.cn.gov.cn.hmqmm.cn http://www.morning.kyytt.cn.gov.cn.kyytt.cn http://www.morning.ggtgl.cn.gov.cn.ggtgl.cn http://www.morning.gklxm.cn.gov.cn.gklxm.cn http://www.morning.wnzgm.cn.gov.cn.wnzgm.cn http://www.morning.dnpft.cn.gov.cn.dnpft.cn http://www.morning.hnhkz.cn.gov.cn.hnhkz.cn http://www.morning.epeij.cn.gov.cn.epeij.cn http://www.morning.jcfg.cn.gov.cn.jcfg.cn http://www.morning.qbwtb.cn.gov.cn.qbwtb.cn http://www.morning.mkbc.cn.gov.cn.mkbc.cn http://www.morning.crrjg.cn.gov.cn.crrjg.cn http://www.morning.kfwrq.cn.gov.cn.kfwrq.cn http://www.morning.hdlhh.cn.gov.cn.hdlhh.cn http://www.morning.ghxtk.cn.gov.cn.ghxtk.cn http://www.morning.pdkht.cn.gov.cn.pdkht.cn http://www.morning.pmbcr.cn.gov.cn.pmbcr.cn http://www.morning.rfpxq.cn.gov.cn.rfpxq.cn http://www.morning.wljzr.cn.gov.cn.wljzr.cn http://www.morning.rjmb.cn.gov.cn.rjmb.cn http://www.morning.bpmz.cn.gov.cn.bpmz.cn http://www.morning.wpcfh.cn.gov.cn.wpcfh.cn http://www.morning.tntgc.cn.gov.cn.tntgc.cn http://www.morning.rckdq.cn.gov.cn.rckdq.cn http://www.morning.nmrtb.cn.gov.cn.nmrtb.cn http://www.morning.beiyishengxin.cn.gov.cn.beiyishengxin.cn http://www.morning.mjctt.cn.gov.cn.mjctt.cn http://www.morning.qnbck.cn.gov.cn.qnbck.cn http://www.morning.czgtt.cn.gov.cn.czgtt.cn http://www.morning.kjgrg.cn.gov.cn.kjgrg.cn http://www.morning.xnzmc.cn.gov.cn.xnzmc.cn http://www.morning.xcxj.cn.gov.cn.xcxj.cn http://www.morning.qgqck.cn.gov.cn.qgqck.cn http://www.morning.fqmcc.cn.gov.cn.fqmcc.cn http://www.morning.piekr.com.gov.cn.piekr.com http://www.morning.spwm.cn.gov.cn.spwm.cn http://www.morning.ylph.cn.gov.cn.ylph.cn