QC API全系列揭秘之Test Execution操作(全网首发)

news2024/9/24 19:25:15

目录

一、QC简介:

二、写作目的:

三、解决问题:

四、本文重点:

五、QC接口规范:

六、QC接口操作Test Execution:

定义全局变量

QC服务器连接、登录(身份验证)及项目连接

重点之一:递归生成业务树

重点之二:测试执行


一、QC简介:

        Quality Center存在至今已经走过了10多个年头,名字从一开始的TD,到后来的QC,再到现在的ALM。所属公司从开始的Mercury到现在的HP,核心一直没变,变的只有名字。随着Mercury最核心的高层、架构师和专家的离开,现在每每的升级都带来诸多失望,再也没有当初使用Mercury工具的时候那样心潮澎湃,看看QC,看看QTP,不多言语。如果能够坚持做好的话,现在哪有TestLink、哪有禅道什么事。然而,QC框架的设计核心,拿到现在来看,依然是测试管理框架的主流。QC设计思路简单清晰,从测试需求到测试用例,再到执行测试用例、提交缺陷、跟踪缺陷,整个过程清晰且易于理解,时至今日,依然被广泛沿用。(微信公众号“诗泽园”)

二、写作目的:

        写此系列的目的,不是为了情怀,而是为了将QC接口的调用方式整理成册。一来是为了通过对QC接口调用的理解,去更深入的理解测试框架的概念(当然仅仅包含小部分);二来是为了通过二次开发,解决QC使用过程中的诸多不便。

三、解决问题:

QC当前存在以下问题:

1、需求或用例的导入导出依然不完善。(网上资料大部分需要admin账户通过后台SQL做关键字筛选获得结果,但事实上与实际的导入导出过程有所出入。)

2、用例执行顺序需要参考已有用例集,无法随心所欲变化。

3、每次执行的用例集列表无法保存并复用。

4、手动执行前需要处理解锁等额外步骤。

5、测试结果随有统一展示,但需要人工收集结果等等。

四、本文重点:

        本文着重介绍Test Execution部分,解决了以上罗列的后几个问题,并为某些问题提供解决的条件。其余需求树、用例树读取及写入部分以后再介绍。
        Test Execution属于自动化测试框架的一部分,我们先从框架说起。
        框架的概念:
        测试框架的话题,范围实在是太大了,我们还是围绕QC来说。我们仅仅考虑从测试用例的编写、测试用例的执行和测试报告来看。用过的同学都清楚,TestPlan里可以存放测试用例,而TestLab里可以建TestSet并形成用例集并且执行,Report里查看用例,这就是基本流程。而对于自动化测试的流程而言,用QC的方式又有所区别:首先,是测试工具的关联。QC需要安装QTP或LR的插件,使得QC的测试执行模块里可以识别这两类代码。又或者你用的是其他第三方工具或用JAVA和.Net自开发的测试工具,那你需要用VB6编写关联脚本,使得QC能够调用你写的代码,这个过程我们不在本文中讨论。其次,是测试脚本的存储。以用例的形式存储在TestPlan里,最终落到QC的后台SQL数据库里,并能实现脚本与数据的分开存储。再者是测试用例集的构成,这部分是放在TestLab里去管理。按照业务逻辑,将已有用例归集并排序,形成业务逻辑并保存。最后是测试执行,按照被测系统版本、范围,选择相应的业务节点去触发执行,获得结果。

        这个过程其实分两个阶段,一个是测试开发阶段,另一个是测试执行阶段,两个阶段各有各的自动化设计方面的考虑。这个不是本文的主旨,但是我也顺便捋一下,加深理解。测试开发阶段,其实是要设计出狭义的测试框架,也就是一个可以团队合作开发的测试脚本的模式,包含底层库、业务的封装、上层调用及断言等等。有了狭义的框架后,需要有偏业务的测试人员介入,将测试脚本归集形成测试集。在测试开发阶段,往往这两块是一同进行的,边改边拼接。测试Q执行阶段,其实是要有测试执行框架去支撑的,尤其是有大批量的测试脚本和测试机需要团队去匹配执行时,这个框架就显得尤为重要。其中涉及到的关键点,如待测范围的选择及保存、测试机的管理(vmware or docker)、用例执行时的动态分配、异常处理、报告收集等等。

        本文所涉及的内容应该是通过QC实现自动化测试脚本运行的前提下,实现测试范围的选择与保存,测试脚本的自动化执行并做后续的报告收集工作。

五、QC接口规范:

        具体的接口规范你可以尝试通过百度查询“QC OTA”或者“QC对象模型”,获得接口说明及使用规范。但以下的核心代码均是本人键盘手打敲击而成,尤其是核心的业务树生成及测试执行部分,均为首次发布。还望转载或代码复用时注明出处。(出自微信公众号“诗泽园”或博客园“朝花夕拾”--https://www.cnblogs.com/alphaxu/)

六、QC接口操作Test Execution:

正式切入正题:

定义全局变量

真实代码中有很多控制类及展示类,都已经去除了。这里只展示核心代码。

1        TDConnection tdc = new TDConnection();
2        TDAPIOLELib.TSScheduler QCscheduler;
3        //用于最终真实启动用例及监测执行结果
4        TDAPIOLELib.ExecutionStatus QCexecutionStatus;
5        //用于反馈执行结果及做结果的动态刷新
6        List QClistForTSTest;

QC服务器连接、登录(身份验证)及项目连接

服务器连接为初始化连接,好比你刚登录QC终端时它给你的反馈。一般会碰到要你reload ActiveX或者OTA初始化失败之类的错误。处理方法是把QC缓存文件夹删除,再访问,让其重新reload。这块代码里会有处理,但这类代码就不贴了。

 1        //初始化连接
 2        private void InitConnect(string serverName)
 3        {
 4            try
 5            {
 6                if ((tdc.Connected == false) || (tdc.Connected == true && tdc.ServerName != serverName))
 7                    tdc.InitConnectionEx(serverName);
 8            }
 9            catch (Exception ex)
10            {
11                Console.WriteLine(ex.ToString());
12                MessageBox.Show("Server Error", "Warning");
13            }
14        }
15
16        //身份验证
17        private void GetAuthenticate(string userName, string passWord)
18        {
19            try
20            {
21                tdc.Login(userName, passWord);
22                TDAPIOLELib.List projectList = tdc.get_VisibleProjects(tdc.VisibleDomains[1].ToString());
23                //VisibleDomains[1]为项目列表中的第一个Domain,多的话自行处理
24                for (int i = 1; i <= projectList.Count; i++)
25                {
26                    projectsBox.Items.Add(projectList[i]);
27                    //将Domain下所有项目读取出来,以备后用
28                }            
29            }
30            catch (Exception ex)
31            {
32                Console.WriteLine(ex.ToString());
33                MessageBox.Show("Please check the User Name is correct or not.", "Warning");
34            }
35        }
 1        //项目连接
 2        private void LoginButton_Click(object sender, EventArgs e)
 3        {
 4            try
 5            {
 6                string ProjectName = projectsBox.SelectedItem.ToString();
 7                tdc.Connect(tdc.VisibleDomains[1].ToString(), ProjectName);
 8
 9                //调用生成业务树代码,也可以不在此处调用
10                Thread td_tree = new Thread(new ThreadStart(this.CreateTreeView));
11                td_tree.Start();
12            }
13            catch (Exception ex)
14            {
15                Console.WriteLine(ex.ToString());
16                MessageBox.Show("Please choose the project.", "Warning");
17            }
18        }

重点之一:递归生成业务树

同样需要新开线程调用,先生成根节点,再递归生成业务树

 1        //生成根节点并调用递归树
 2        private void CreateTreeView()
 3        {
 4            try
 5            {
 6                TreeNode mainNode = new TreeNode();
 7                mainNode.Name = "Root";
 8                mainNode.Text = "Root";
 9                Add_TreeRoot(mainNode);
10
11                SysTreeNode test_folder;
12                TestSetFactory globalTestSetFactory;
13                List l_List;
14                TreeNode r_node = new TreeNode();
15
16                int nodeCount;
17                nodeCount = qcProjectTree.GetNodeCount(true);
18                TreeNode[] r_nodeArray = new TreeNode[10000];
19                r_nodeArray = qcProjectTree.Nodes.Find("Root", false);
20                r_node = r_nodeArray[0];
21
22                TestSetTreeManager tm;
23                tm = (TDAPIOLELib.TestSetTreeManager)tdc.TestSetTreeManager;
24                test_folder = (TDAPIOLELib.SysTreeNode)tm.Root;
25                globalTestSetFactory = (TDAPIOLELib.TestSetFactory)tdc.TestSetFactory;
26                l_List = globalTestSetFactory.NewList("");
27                recursiveTreeBuilder(test_folder, r_node);
28            }
29            catch (Exception ex)
30            {
31                Console.WriteLine(ex.ToString());
32            }
33        }
34
35        //递归生成业务树
36        private bool recursiveTreeBuilder(TDAPIOLELib.SysTreeNode folder, TreeNode parent)
37        {
38            TDAPIOLELib.List folders, tests;
39            TDAPIOLELib.TestSetFactory objTestSetFactory;
40            TDAPIOLELib.TestSetFolder objTSFolder;
41            TreeNode n;
42            try
43            {
44                folders = folder.NewList();
45                foreach (TDAPIOLELib.SysTreeNode f in folders)
46                {
47                    TreeNode nodeChild = new TreeNode();
48                    nodeChild.Name = f.Name;
49                    nodeChild.Text = f.Name;
50                    nodeChild.ImageIndex = 0;
51                    Add_TreeNode(parent, nodeChild);
52                    n = parent.Nodes[nodeChild.Name];
53                    recursiveTreeBuilder(f, n);
54                }
55
56                objTSFolder = (TDAPIOLELib.TestSetFolder)folder;
57                if (objTSFolder.NodeID != 0)
58                {
59                    objTestSetFactory = (TDAPIOLELib.TestSetFactory)objTSFolder.TestSetFactory;
60                    tests = objTestSetFactory.NewList("");
61                    foreach (TDAPIOLELib.TestSet testSet in tests)
62                    {
63                        TreeNode nodeChild1 = new TreeNode();
64                        nodeChild1.Name = testSet.ID.ToString();
65                        nodeChild1.Text = testSet.Name;
66                        nodeChild1.ImageIndex = 1;
67                        Add_TreeNode(parent, nodeChild1);
68                        n = parent.Nodes[nodeChild1.Name];
69                        n.Tag = objTSFolder.Path + @"\" + testSet.Name;
70                    }
71                }
72                return true;
73            }
74            catch (Exception ex)
75            {
76                Console.WriteLine(ex.ToString());
77                return false;
78            }
79        }

以下代码用委托的方式生成节点,保证在业务树生成过程中可随时点击并保证界面不出现假死(跟业务树生成无直接关系,可忽略)

 1        delegate void Add_Node(TreeNode parent, TreeNode node);
 2        private void Add_TreeNode(TreeNode parent, TreeNode node)
 3        {
 4            if (this.InvokeRequired)
 5            {
 6                this.BeginInvoke(new Add_Node(Add_TreeNode), parent, node);
 7            }
 8            else
 9            {
10                parent.Nodes.Add(node);
11            }
12            Thread.Sleep(10);
13        }

生成业务树后,由用户通过业务树选择需要运行的节点,形成待测试列表,就是后续代码中的TestSetList,这部分代码跟QC无关,也不列举了。

重点之二:测试执行

先看一个总体调用RunTestSetPlan,当然也是需要新开线程调用的:

1        Thread td_runTestSetPlan = new Thread(new ThreadStart(this.RunTestSetPlan));
2        td_runTestSetPlan.Start();

调用步骤是先检验validate,然后运行run,最后收集结果monitor:

 1        private void RunTestSetPlan()
 2        {
 3            try
 4            {
 5                if (tdc.ProjectConnected == true)
 6                {
 7                    if (TestSetNameList.Items.Count != 0)
 8                    {
 9                        for (int i = 0; i < TestSetList.Items.Count; i++)
10                        {
11                            if (validateTestSetID(TestSetList.Items[i].ToString(), i) == true)
12                            {
13                                if (runTestSet(TestSetList.Items[i].ToString(), i) == true)
14                                {
15                                    if (monitorTestSet(TestSetList.Items[i].ToString()) == true)
16                                    {
17                                        QCexecutionStatus.RefreshExecStatusInfo("all", true);                      
18                                    }
19                                }
20                            }
21                        }
22                    }
23                    else
24                        MessageBox.Show("Empty Test Set List.", "Warning");
25                }
26                else
27                    MessageBox.Show("Connection Error, please login again.", "Warning");
28            }
29            catch (Exception ex)
30            {
31                Console.WriteLine(ex.ToString());
32            }
33        }

validate通过QCfilter,使用testSetID去做筛选,取得我们需要的测试集,然后根据判断测试集是否为空来确定测试集是否有效,代码如下:

 1        private bool validateTestSetID(string testSetID, int i)
 2        {
 3            TDAPIOLELib.TestSetFactory QCtestSetFactory = (TDAPIOLELib.TestSetFactory)tdc.TestSetFactory;
 4            TDAPIOLELib.TDFilter QCfilter = (TDAPIOLELib.TDFilter)QCtestSetFactory.Filter;
 5            QCfilter["CY_CYCLE_ID"] = testSetID;
 6            List QClist = QCfilter.NewList();
 7            if (QClist.Count != 0)
 8            {
 9                return true;
10            }
11            else
12            {
13                return false;
14            }             
15        }

runTest与之前类似,获取首只测试集对象后,通过QCTSTestFactory将测试集下的所有用例形成QClistForTSTest列表,并用QCscheduler执行,代码如下:

 1        private bool runTestSet(string testSetID, int i)
 2        {
 3            try
 4            {
 5                TDAPIOLELib.TestSetFactory QCtestSetFactory = (TDAPIOLELib.TestSetFactory)tdc.TestSetFactory;
 6                TDAPIOLELib.TDFilter QCfilter = (TDAPIOLELib.TDFilter)QCtestSetFactory.Filter;
 7                QCfilter["CY_CYCLE_ID"] = testSetID;
 8                List QClist = QCfilter.NewList();
 9                TDAPIOLELib.TestSet QCtestSet = (TDAPIOLELib.TestSet)QClist[1];
10                TDAPIOLELib.TestSetFolder QCtestSetFolder = (TDAPIOLELib.TestSetFolder)QCtestSet.TestSetFolder;
11                TDAPIOLELib.TSTestFactory QCTSTestFactory = (TDAPIOLELib.TSTestFactory)QCtestSet.TSTestFactory;
12                QClistForTSTest = QCTSTestFactory.NewList("");
13                try
14                {
15                    string applicationCreationTime = File.GetCreationTime(@"The path of Your application").ToString();
16                    string machineName = System.Net.Dns.GetHostEntry("IP address of test machine").HostName.Split('.')[0];
17                    QCtestSet["CY_USER_01"] = applicationCreationTime;
18                    Thread.Sleep(1000);
19                    QCtestSet["CY_USER_02"] = machineName;
20                    Thread.Sleep(1000);
21                    QCtestSet.ResetTestSet(false);
22                    Thread.Sleep(1000);
23                    QCtestSet.Post();
24                    Thread.Sleep(1000);
25                    QCtestSet.Refresh();
26
27                    Thread.Sleep(10000);
28
29                    QCscheduler = (TDAPIOLELib.TSScheduler)QCtestSet.StartExecution("");
30                    QCscheduler.Run(QClistForTSTest);
31                    Thread.Sleep(5000);
32
33                    return true;
34                }
35                catch (Exception ex)
36                {
37                    Console.WriteLine(ex.ToString());
38                    return false;
39                }
40            }
41            catch (Exception ex)
42            {
43                Console.WriteLine(ex.ToString());
44                return false;
45            }
46        }

Monitor,使用QCTestExecStatus中的QCexecutionStatus作为计数器,逐个判断当前步骤是否跑完,汇总运行结果,代码如下:

 1        private bool monitorTestSet(string testSetID)
 2        {
 3            try
 4            {
 5                QCexecutionStatus = (TDAPIOLELib.ExecutionStatus)QCscheduler.ExecutionStatus;
 6                QCexecutionStatus.RefreshExecStatusInfo("all", true);
 7                TDAPIOLELib.TestExecStatus QCTestExecStatus;
 8                int checkStep = 1;
 9                while (checkStep <= QCexecutionStatus.Count)
10                {
11                    QCexecutionStatus.RefreshExecStatusInfo("all", true);
12                    QCTestExecStatus = (TDAPIOLELib.TestExecStatus)QCexecutionStatus[checkStep];
13                    if (QCTestExecStatus.Message == "Nothing" || QCTestExecStatus.Message == "Waiting..." || QCTestExecStatus.Message == "Connecting...")
14                    {
15                        Thread.Sleep(10000);
16                        QCexecutionStatus.RefreshExecStatusInfo("all", true);
17                    }
18                    else
19                    {
20                        TDAPIOLELib.TSTest QCtestOfTestSet = (TDAPIOLELib.TSTest)QClistForTSTest[checkStep];
21                        QCtestOfTestSet.Refresh();
22                        switch (QCTestExecStatus.Message)
23                        {
24                            case "Completed":
25                                if (QCtestOfTestSet.Status == "Passed")
26                                    CurrentStateBar("Step " + checkStep + " " + QCtestOfTestSet.Name + " execution completed -> " + QCtestOfTestSet.Status);
27                                else
28                                    if (QCtestOfTestSet.Status == "Failed")
29                                        CurrentStateBar("Step " + checkStep + " " + QCtestOfTestSet.Name + " execution completed -> " + QCtestOfTestSet.Status);
30                                    else
31                                        CurrentStateBar("Step " + checkStep + " " + QCtestOfTestSet.Name + " execution unknown -> " + QCtestOfTestSet.Status);
32                                break;
33                            case "No available hosts":
34                                CurrentStateBar("Step " + checkStep + " " + QCtestOfTestSet.Name + " execution failed (No available hosts) -> " + QCtestOfTestSet.Status);
35                                break;
36                            case "Cannot get RemoteAgent's ClassID for test type <TestType>":
37                                CurrentStateBar("Step " + checkStep + " " + QCtestOfTestSet.Name + " Cannot get RemoteAgent's ClassID for test type <TestType> -> " + QCtestOfTestSet.Status);
38                                break;
39                            case "Host connected":
40                                CurrentStateBar("Step " + checkStep + " " + QCtestOfTestSet.Name + " execution failed (Host connected) -> " + QCtestOfTestSet.Status);
41                                break;
42                            default:
43                                CurrentStateBar("Step " + checkStep + " " + QCtestOfTestSet.Name + " unhandled case -> " + QCtestOfTestSet.Status);
44                                break;
45                        }
46                        checkStep = checkStep + 1;
47                    }
48                }
49                return true;
50            }
51            catch (Exception ex)
52            {
53                Console.WriteLine(ex.ToString());
54                return false;
55            }
56        }

至此,整个测试运行过程结束。关于收集结果中除了主线程结果刷新之外,还需要有其他线程做结果的收集和展示,否则无法实现动态实时展示,这部分代码与QC无直接关系,也暂时不展示。

可以看出,本文所涉及的内容,对于测试框架来说,也仅仅是一小部分。关于其他部分,以后有时间再分拆开逐一讨论。


 以下是我收集到的比较好的学习教程资源,虽然不是什么很值钱的东西,如果你刚好需要,可以评论区,留言【777】直接拿走就好了

各位想获取资料的朋友请点赞 + 评论 + 收藏,三连!

三连之后我会在评论区挨个私信发给你们~

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

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

相关文章

小程序商城系统的开发方式及优缺点分析

小程序商城系统是一种新型的电子商务平台&#xff0c;它通过小程序的形式为商家提供了一种全新的销售渠道&#xff0c;同时也为消费者提供了一种便捷的购物体验。小程序商城系统具有低成本、快速上线、易于维护等特点&#xff0c;因此在市场上受到了广泛的关注和应用。这里就小…

【设计模式——学习笔记】23种设计模式——模板方法模式Template Method(原理讲解+应用场景介绍+案例介绍+Java代码实现)

介绍 基本介绍 模板方法模式&#xff0c;又叫模板模式&#xff0c;在一个抽象类中定义了一个执行它的其他方法的公开模板方法&#xff0c;子类可以按需重写抽象类的抽象方法简单说&#xff0c;模板方法模式 定义一个操作中的算法&#xff08;或者说流程&#xff09;的骨架&am…

Vue引入

1. vue引入 第一种方法&#xff1a;在线引入 <script src"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 第二种方法&#xff1a;本地引入 2. 语法学习 el用于绑定id&#xff0c;data用于定义数据如下例题 <!DOCTYPE html> <html…

xinput1_4.dll丢失的解决方法,三种解决方法分享

xinput1_4.dll是一个动态链接库文件&#xff08;DLL&#xff09;&#xff0c;它是Microsoft DirectX的一部分&#xff0c;用于处理游戏控制器输入。当你的电脑提示xinput1_4.dll文件丢失时&#xff0c;意味着与这个文件相关的游戏或应用程序无法正常运行。 当你的电脑提示xinp…

正负样本分配策略(OTA, SimOTA,TAS)

文章目录 OTASimOTATALATSS OTA 论文&#xff1a;《OTA: Optimal Transport Assignment for Object Detection》 代码&#xff1a;Megvii-BaseDetection/OTA 标签分配算法 目标CNN-based的目标检测器是预测 pre-defined anchors 的类别 (cls) 以及偏移量 (reg) 。 为了训练目标…

go 结构体 - 值类型、引用类型 - 结构体转json类型 - 指针类型的种类 - 结构体方法 - 继承 - 多态(interface接口) - 练习

目录 一、结构体 1、python 与 go面向对象的实现&#xff1a; 2、初用GO中的结构体&#xff1a;&#xff08;实例化一个值类型的数据&#xff08;结构体&#xff09;&#xff09; 输出结果不同的三种方式 3、实例化一个引用类型的数据&#xff08;结构体&#xff09; 4、…

esp32 wifi无线透传

wifi无线透传 目录 wifi无线透传[TOC](目录) 一、Esp32代码1.1 下载烧写 二、星空内网穿透配置2.1 平台注册2.2 充值2元(用于实名认证)2.3 实名认证2.4 创建隧道2.5 下载软件2.6 配置文件2.7 启动服务 因为常见的无线传输视频或图片&#xff0c;只能在局域网内中实现&#xff0…

【并发专题】手写MyReentantLock

分析 ReentantLock的特点如下&#xff1a; 首先是继承自AQS的可中断可以设置超时时间可以切换公平锁/非公平锁支持多个条件变量支持可重入 事实上&#xff0c;上面的很多东西AQS已经帮忙实现了&#xff0c;所以想要复刻一个不是很难。仔细观察一下源码&#xff0c;我们需要重…

Text-to-SQL小白入门(一)

摘要 本文主要介绍了Text-to-SQL研究的定义、意义、研究方法以及未来展望&#xff0c;主要是对Text-to-SQL领域进行一个初步的认识和了解&#xff0c;适合初学者入门了解。 1 引言 作为Text-to-SQL领域的小白&#xff0c;学习该领域的最好方式就是看最新的综述文章&#xff…

Junit4入门之什么是单元测试?

干了一年多的后端了&#xff0c;从来没有了解过单元测试。虽然我知道测试不仅仅是测试们的任务&#xff0c;后端也要进行自测来保证自己的代码的可用性&#xff0c;但我一直都只是用postman来实施的&#xff0c;调用调通了即可。虽然我也知道Junit是用于测试的软件&#xff0c;…

几种常用到的 Hybrid App 框架方案

移动操作系统在经历了诸神混战之后&#xff0c;BlackBerry OS、Symbian OS、Windows Phone等早期的移动操作系统逐渐因失去竞争力而退出。目前&#xff0c;市场上主要只剩下安卓和iOS两大阵营&#xff0c;使得iOS和安卓工程师成为抢手资源。然而&#xff0c;由于两者系统的差异…

学了python的心得体会200字,学python心得体会1000字

大家好&#xff0c;本文将围绕学了python的心得体会200字展开说明&#xff0c;学python心得体会1000字是一个很多人都想弄明白的事情&#xff0c;想搞清楚学python心得体会800字需要先了解以下几个事情。 一、个人学期总结 本学期在missdu的带领下&#xff0c;进行了python的学…

Jenkins通过OpenSSH发布WinServer2016

上一篇文章> Jenkins集成SonarQube代码质量检测 一、实验环境 jenkins环境 jenkins入门与安装 容器为docker 主机IP系统版本jenkins10.10.10.10rhel7.5 二、OpenSSH安装 1、下载 官网地址&#xff1a;https://learn.microsoft.com/zh-cn/windows-server/administration/op…

Spring Boot的创建和运行

目录 1.Spring Boot的优点 2.Spring Boot项目创建 2.1使用Idea创建 2.2网页版创建 3.项目目录介绍和运行 3.1运行项目 3.2输出 4.注意事项 4.1正确路径 4.2小结&#xff1a;约定大于配置 1.Spring Boot的优点 ●快速集成框架&#xff0c;Spring Boot 提供了启动添…

解决:Uncaught (in promise) SyntaxError: “[object Object]“ is not valid JSON 问题的过程

1、问题描述&#xff1a; 其一、报错为&#xff1a; Uncaught (in promise) SyntaxError: "[object Object]" is not valid JSON 中文为&#xff1a; 未捕获&#xff08;承诺中&#xff09;语法错误&#xff1a;“[object Object]”不是有效的 JSON 其二、问题描…

阿丹千问vue页面升级-使用Markdown形式展示回答--markdown-it库

阿丹&#xff1a; 在之前开发的阿丹千问 发现回复的文章格式使用 Markdown的格式。所以想使用Markdown的方式来给页面来个升级。 下面就是升级以及开发的过程。 升级思路 使用vue中的markdown-it库 在Vue页面中使用Markdown文档 安装markdown-it&#xff1a; 在Vue项目中…

《HeadFirst设计模式(第二版)》第一章源码

代码文件目录结构&#xff1a; FlyBehavior.java package Chapter1_StrategyPattern.ch1_3_behavior.behaviors.fly;public interface FlyBehavior {void fly(); } FlyNoWay.java package Chapter1_StrategyPattern.ch1_3_behavior.behaviors.fly;public class FlyNoWay imp…

使用Jetpack Compose构建时间轴组件的逐步指南

使用Jetpack Compose构建时间轴组件的逐步指南 最近&#xff0c;我们开发一个时间轴组件&#xff0c;显示用户与客户之间的对话。每个对话节点应具有自己的颜色&#xff0c;取决于消息的状态&#xff0c;并且连接消息的线条形成颜色之间的渐变过渡。 我们慷慨地估计了未来的工…

C++学习day--18 空指针和函数指针、引用

1、void 类型指针 void > 空类型 void* > 空类型指针&#xff0c; 只存储地址的值&#xff0c;丢失类型&#xff0c;无法访问&#xff0c;要访问其值&#xff0c;我们必须对这个指 针做出正确的类型转换&#xff0c;然后再间接引用指针 。 所有其它类型的指针都可以隐…