单元测试框架unittest

unittest是Python语言的单元测试框架,在Python的官方文档中,对unitest单元测试框架进行了详细的介绍。 https://docs.python.org/3/library/unittest.html

unittest单元测试框架提供了创建测试用例、测试套件和批量执行测试用例的方案。在python安装成功后,unittest单元测试框架就可以直接导入使用,它属于标准库。作为单元测试的框架,unittest单元测试框架也是对程序的最小模块进行的一种敏捷化测试。

利用单元测试框架,可以创建一个类,该类继承unittest的TestCase,这样可以把每个TestCase看成是一个最小单元,由测试套件组织起来,运行时直接执行即可,同时可引入测试报告。

  • 测试固件

在unittest单元测试框架中,测试固件用于处理初始化的操作,例如,在对百度的搜索进行测试之前,首先需要打开浏览器并且进入百度首页;测试结束后,需要关闭浏览器。测试固件提供了两种执行方式,一种是每次执行一个测试用例,测试固件都会被执行到;另外一种是不管有多少个测试用例,测试固件只执行一次。

测试固件每次都执行

import unittest
 class DemoTest(unittest.TestCase):
   def setUp(self):    #1
         print('start')
   def tearDown(self): #3     
     print('end') 
   def test_add_story(self):   #2     
     print('测试用例1执行') 
   def test_edit_story(self):     
     print('测试用例2执行')
 if name == 'main':
     unittest.main(verbosity=2)

执行结果:

执行顺序是先执行setUp方法,再执行具体的测试用例test_add_story, 最后执行tearDown方法,这个过程执行两次,如果在一个测试类中有N个测试用例,那么也就意味着着打开N次浏览器,关闭N次浏览器,而关闭和打开浏览器都会占用一定的资源和时间,很显然,性能不好,执行时间长

from selenium import webdriver
import unittest
import time as t
class DemoTest(unittest.TestCase):
def setUp(self):    #1     
    self.driver = webdriver.Chrome()     
    self.driver.maximize_window() 
    self.driver.implicitly_wait(30) 

def tearDown(self): #3     
    t.sleep(5)     
    self.driver.quit() 

def test_add_story(self):   #2     
    print('执行新增需求测试用例')
  …………

def test_delete_story(self):     
    print("执行删除需求测试用例")     
  …………

def _add_data_to_name_and_description(self, name, description):
    …………
 
if name == 'main':
     # unittest.main(verbosity=2)
     suite = unittest.TestSuite()
     suite.addTest(DemoTest("test_add_story"))
     suite.addTest(DemoTest("test_edit_story"))
     suite.addTest(DemoTest("test_delete_story"))
     #执行测试
     runner = unittest.TextTestRunner()
     runner.run(suite)   

unittest的main()方法执行用例的顺序是按照测试类、测试方法的名字的ASCII顺序来执行测试方法。如果想要控制执行顺序,有以下两种方式:

  • 通过TestSuite按照顺序添加想要执行的方法,上面的代码用的就是此方法
  • 顺应testunit的执行顺序,就是通过控制方法名字来实现

测试固件只执行一次

钩子方法setUp和tearDown虽然经常使用,但是在UI自动化测试中,一个系统的测试用例一般多达五百多条,打开和关闭五百次浏览器,会消耗大量的资源和时间。在unittest单元测试框架中可以使用另外一个测试固件来解决这一问题,它就是setUpClass和tearDownClass方法。该测试固件方法是类方法,需要在方法上面加装饰器@classmethod。使用该测试固件,不管多少个测试用例,测试固件只执行一次,也就是说不管多少个测试用例,执行的时候,浏览器只被打开一次和关闭一次。

Selenium自动化测试基础

1.访问页面、find_element_by_name选取元素、访问iframe、提交表单

#引入webdriver
from selenium import webdriver
import time as t

driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(30)
driver.get("http://xxxxx/yyyy")

#添加需求标题
driver.find_element_by_name("data[Story][name]").send_keys("添加需求测试用例")
#添加需求详细描述
iframe = driver.find_element_by_tag_name("iframe")
# driver.switch_to_frame(iframe) //旧版切换iframe
driver.switch_to.frame(iframe)
#清空详细描述
driver.find_element_by_tag_name("body").clear()
#填写需求详细描述
driver.find_element_by_tag_name("body").send_keys("添加需求测试用例");
#切换回父页面
driver.switch_to.default_content()
# 点击提交按钮
# driver.find_element_by_id("btn_save_view").click()
# 提交表单
driver.find_element_by_id("FormStory").submit()
t.sleep(5)
driver.quit()

2. find_element_by_xpath XPath方式选取元素

!/usr/bin/python3
 --coding:utf-8 --
from selenium import webdriver
import time as t

driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(30)
 driver.get("http://xxxxx/yyyy")
# find_element_by_xpath选取元素
a_link = driver.find_element_by_xpath('//*[@id="searchable"]/div[3]/div/ul/li[2]/p[2]/a')
a_link.click();
t.sleep(5)
driver.quit()

Chrome控制台选中元素,Copy XPath 可以复制出XPath

3.find_element_by_css_selector方式选取元素,execute_script执行js

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
import time as t
#up = "window.scrollTo(0,0)"
#down = "window.scrollTo(0,document.body.scrollHeight)"
#tui-b是一个带滚动条的容器
#滚动到最顶端
up = "document.querySelector('.tui-b').scrollTop=0"
#滚动条向下滚100px
down = "document.querySelector('.tui-b').scrollTop=100"
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("http://xxxxx/yyyy");
#向下滚动,以便看到update_status_btn按钮
driver.execute_script(down)
driver.find_element_by_css_selector("#update_status_btn").click()
t.sleep(4)
driver.quit()

4.得到当前页面的地址

from selenium import webdriver

driver = webdriver.Chrome()
driver.maximize_window() //最大化窗口
driver.implicitly_wait(30)
driver.get("http://xxx.yyyy")
print('测试地址为: {0}'.format(driver.current_url))
driver.quit()

5.得到当前页面的源码

from selenium import webdriver

driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(30)
driver.get("http://www.xxxx.com")
print('页面代码如下: {0}'.format(driver.page_source))
driver.quit()

6.得到当前页面的标题

driver = webdriver.Chrome()
print('页面标题:{0}'.format(driver.title))

7.判断元素是否选中

from selenium import webdriver
import time as t

driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(30)
driver.get("www.sss.com")
login_remember = driver.find_element_by_id("chkWeek")
print("是否记住login: {0}".format(login_remember.is_selected()))
login_remember.click()
print("是否记住login: {0}".format(login_remember.is_selected()))
driver.quit()

8.选取链接元素

from selenium import webdriver
driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(30)
driver.get("www.yyy.com")
obj = driver.find_element_by_link_text(u"添加需求测试用例")
obj = driver.find_element_by_partial_link_text(u'添加需求测试')
obj.click()
driver.quit()

9.下拉选择框select的定位

from selenium.webdriver import ActionChains
import time as t
driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(30)
driver.get("http://www.baidu.com")
t.sleep(3)
element = driver.find_element_by_link_text(u'设置')
t.sleep(2)
ActionChains(driver).move_to_element(element).perform()
t.sleep(3)
driver.find_element_by_css_selector('.setpref').click()
t.sleep(3)
nr= driver.find_element_by_id('nr')
select = Select(nr)
select.select_by_visible_text('每页显示20条')  #按文本选择
select.select_by_index(2)    #50 按索引值选择
select.select_by_value('20') #按option的value值选择, 记得要引号
print('下拉框选择的最新条数是:', nr.get_attribute('value'))
t.sleep(3)
driver.quit()

10.原生alert框的定位

from selenium import webdriver
from selenium.webdriver.support.select import Select
//需要的库
from selenium.webdriver.common.alert import Alert
from selenium.webdriver.common.action_chains import ActionChains
import time as t
driver = webdriver.Chrome()
driver.maximize_window()
driver.implicitly_wait(30)
driver.get("http://www.baidu.com")
t.sleep(3)
element = driver.find_element_by_link_text(u'设置')
t.sleep(2)
ActionChains(driver).move_to_element(element).perform()
t.sleep(3)
driver.find_element_by_css_selector('.setpref').click()
t.sleep(3)
nr= driver.find_element_by_id('nr')
select = Select(nr)
select.select_by_visible_text('每页显示20条')
select.select_by_index(2)    #50
select.select_by_value('20')
print('下拉框选择的最新条数是:', nr.get_attribute('value'))
t.sleep(3)
driver.find_element_by_css_selector('.prefpanelgo').click()
t.sleep(2)
#获取alert框的文本信息  //关键语句
print('alert框的文本:{0}'.format(driver.switch_to.alert.text))
#点击alert框的确定按钮  //关键语句
driver.switch_to.alert.accept()
driver.quit()

Scrum详解

Scrum是迭代式增量软件开发过程,通常用于敏捷软件开发
用7句话概括一下:[出自《知行合一:实现价值驱动的敏捷和精益开发》一书]

  • 产品经理(Product Owner)负责建立并维护一个按优先级次序排列的、反映客户期望的产品需求列表(Product backlog)
  • 在迭代(sprint)计划时,团队从需求列表中优先级高的需求项中选取一小部分,放入迭代需求列表(sprint backlog)中,并决定如何开发这些需求功能
  • 团队在固定的时间周期内完成一个迭代,通常是2-4周,团队每天会在一起评估项目进展情况(daily scrum)
  • 在这个过程中,Scrum过程经理(Scrum Master)会让团队关注迭代目标的实现并遵循Scrum实践
  • 在每次迭代结束时,团队完成的代码是可以提交的:可以直接让客户使用,或者可以展示给客户或用户代表
  • 迭代的最后两个活动是迭代评审(sprint review)和迭代回顾(sprint retrospective),根据反馈,对产品及团队工作方式(过程)做优化调整
  • 在下个迭代开始时,Scrum团队(Scrum team)又会从产品需求列表中选取一部分优先级高的需求项,开始新一轮的开发工作
典型的Scrum管理框架

有人把Scrum简单解释为3个角色,3个文档和5个会议:

Scrum管理框架中的3个角色是产品经理,Scrum Master(Scrum 过程经理)和Scrum团队(Scrum team)

产品经理最主要的责任是保证团队开发的功能特性对客户是有价值的,具体来说,他需要做以下5件事:

  • 建立产品的愿景,也就是产品给客户带来的价值
  • 建立维护产品的发布计划/版本计划(release plan)
  • 及时收集用户反馈、优化产品需求
  • 确定每条需求项(User Story)的价值及优先级
  • 明确每个需求项的验收通过标准

Scrum Master比较特殊,在传统方法中是没有这个角色的,所以这个是经常被误解的角色。一个称职的SM(过程经理)能在3个方面起到重要作用:

  • 让团队关注点始终在实现客户价值上;
  • 让团队在每个迭代中不受干扰(大家都知道封闭式开发能保证效率,Scrum的每一次迭代就是不需要团队成员住酒店的封闭式开发);
  • 帮助产品经理和团队在Scrum的框架下做好各自的工作,并做到有效的沟通。

SM[Scrum Master]为了实现上面3个目标,SM需求做好以下一些工作:

  • 建立、改进适用于团队的Scrum过程
  • 推动敏捷实践及有效开发实践在开发中的有效应用
  • 推动团队问题障碍的解决
  • 帮助培养团队的自我管理开成良好的团队文化
  • 协调各方的沟通

SM不是真正意义上的经理,不是传统的项目经理,他和团队成员之间不是管理与被管理的关系。SM更像是团队的过程教练。

我个人作为SM时,实际需要做的事:

  • 修改各特性小组名称,以作知会
  • 信使会之前与相关产品、技术人员确定本迭代的大致需求范围;(产品需求不需要了解太过细节。但技术类的需要仔细与相关人员确认)
  • 参加信使会,积极参与讨论,发表自己看法,了解需求背景、目的等信息,记录其他特性小组的需求;(包括父需求、阶段目标等)
  • IPM前,提前过一遍下个迭代的用户需求,和产品沟通User Story的可行性和注意点[主要是如何在现有系统的基础上快速实现用户需求,比如哪些是可实现的,哪些是可能需要增加额外工作量的]
  • 参加本特性小组IPM时,在开会之前作其他特性小组的关键需求介绍,并回答其他成员的提问
  • 迭代中,在晨会、讨论会、工作群中关注迭代进度,及时发现潜在风险(如技术、资源、沟通等问题),尤其是在进度方面的问题。对于能够解决的问题进行跟进或组织讨论
  • 在迭代快结束的时候,提醒团队成员及时扭转需求和产品的封版时间
  • 迭代封版后,针对规模是3或者某些重点需求,如果尚未流转,则需要跟负责人进行沟通,了解是否能正常流转,并将之反馈在信使群中
  • 在迭代结束后,组织迭代评审和迭代回顾

Scrum框架下的最后一个角色是开发团队(Scrum team),开发团队是Scrum过程的核心。这是个规模小(5-9人)的团队,一般是一个Feature Team,团队应具备的软件开发所需要的所有技能:需求分析、设计、编码、测试、技术资料编写等。它的主要责任是通过迭代,不断开发提交对客户有价值的功能特性,同时持续改进提升团队能力,将其潜能最大化。团队主要工作包括:

  • 估计产品需求列表中用户故事的复杂度,考虑用户故事的优先级、依赖关系、实现难度等,选择下个迭代的范围,形成迭代需求列表[这个形成迭代需求列表一般由产品经理来规划,开发只在IPM上估算需求规模工作量]
  • 遵循团队达成的工程实践共识,完成每个用户故事的需求澄清、设计、编码、评审、测试、资料编写等相关工作,不断提交对客户有价值的需求功能
  • 不断总结开发过程中的得与失,持续改进个人能力及团队能力

Scrum管理框架中的3个文档:

  • 产品需求列表,产品需求列表是Scrum中最重要的文档,它是一个动态的,产品经理可以随时对其进行调整的,包含了客户期望的需求列表清单。大部分敏捷团队用“用户故事”的形式来表示每一个需求项,产品经理会对它们按价值高低排序
  • 迭代需求列表,是由团队负责管理,它定义了Scrum团队某次迭代承诺实现的用户故事或任务。在迭代中,它一般是不变的,偶尔会在IPM上有所调整,比如视成员数的增减,休假情况来调整
  • 燃尽图是Scrum中的第三个文档,它主要是用来监控版本及迭代开发进展情况。版本燃尽图显示本次版本未开发的需求项或剩余的工作,而迭代燃尽图则显示一次迭代中未完成的工作。
版本燃尽图
迭代燃尽图

燃尽图可以清晰的展示版本实现情况和迭代完成情况

Scrum管理框架中的5个会议:

  • 产品需求列表的细化会议:团队和产品经理一起会细化列在需求列表前面的需求项,为近几次的迭代做好准备,这个在我所在团队由产品经理完成
  • 迭代计划会议(IPM):团队从产品需求列表前面被细化的需求项中选择本次迭代要完成的用户故事或任务,形成迭代需求列表,IPM上一般开发团队一起来就用户故事估算故事规模点/工作量
  • 每日站会
  • 迭代评审会议:showcase 本次迭代中团队完成的需求功能,让产品经理、客户及其他利益相关人加深对产品的理解,调整产品需求列表,逐步识别聚焦到真正对客户有价值的需求特性。
  • 迭代回顾会议:会列出本迭代或是近期迭代中团队的well和less well

Scrum中的一个重要时间盒体现在固定的迭代周期(一般2-4周),固定时长的产品需求列表细化会议(2-4小时),固定时长的迭代计划会议(半天时长),固定时长的每日站会(5-10分钟),固定时长的迭代评审会议(2-4个钟)和固定时长的迭代回顾会议(2-4个钟)。时间盒是使团队专注、发挥潜能,及早发现问题并做出解决决策的有效手段。

以上为Scrum的主要内容,Scrum和XP是常见的敏捷开发方法

Jenkins 构建工具教程

文章来源:https://www.jianshu.com/p/5f671aca2b5a (个人觉得写的不错)

Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具,起源于Hudson(Hudson是商用的),主要用于持续、自动的构建/测试软件项目、监控外部任务的运行(这个比较抽象,暂且写上,不做解释)。Jenkins用Java语言编写,可在Tomcat等流行的Servlet容器中运行,也可独立运行。通常与版本管理工具(SCM)、构建工具结合使用。常用的版本控制工具有SVN、GIT,构建工具有Maven、Ant、Gradle。

CI(Continuous integration,中文意思是持续集成)是一种软件开发时间。持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。借用网络图片对CI加以理解

CD(Continuous Delivery, 中文意思持续交付)是在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的Staging环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境。下图反应的是CI/CD 的大概工作模式。

三、使用Jenkins进行PHP代码(单元)测试、打包。

Jenkins是一个强大的CI工具,虽然本身使用Java开发,但也能用来做其他语言开发的项目CI。下面讲解如何使用Jenkins创建一个构建任务。 登录Jenkins, 点击左侧的新建,创建新的构建任务。

跳转到如下界面。任务名称可以自行设定,但需要全局唯一。输入名称后选择构建一个自由风格的软件项目(其他选项不作介绍)。并点击下方的确定按钮即创建了一个构建任务。之后会自动跳转到该job的配置页面。

下图是构建任务设置界面,可以看到上方的几个选项“General”, “源码管理”, “构建触发器”,”构建环境”, “构建”, “构建后操作”。下面逐一介绍。

1.General

General是构建任务的一些基本配置。名称,描述之类的。

项目名称: 是刚才创建构建任务步骤设置的,当然在这里也可以更改。
描述: 对构建任务的描述。  
丢弃旧的构建: 服务器资源是有限的,有时候保存了太多的历史构建,会导致Jenkins速度变慢,并且服务器硬盘资源也会被占满。当然下方的”保持构建天数” 和 保持构建的最大个数是可以自定义的,需要根据实际情况确定一个合理的值。其他几个选项在这里不做介绍,有兴趣的可以查看Jenkins”帮助信息”, 会有一个大概的介绍。不过这些”帮助信息”都是英文的。

2.源码管理

源码管理就是配置你代码的存放位置。

Git: 支持主流的github 和gitlab代码仓库。因我们的研发团队使用的是gitlab,所以下面我只会对该项进行介绍。
Repository URL:仓库地址
Credentials:凭证。可以使用HTTP方式的用户名密码,也可以是RSA文件。 但要通过后面的”ADD”按钮添加凭证。
Branches to build:构建的分支。*/master表示master分支,也可以设置为其他分支。
源码浏览器:你所使用的代码仓库管理工具,如github, gitlab.  
URL:填入上方的仓库地址即可。
Version: 8.7   这个是我们gitlab服务器的版本。
Subversion:就是SVN,这里不作介绍。

3.构建触发器

构建触发器,顾名思义,就是构建任务的触发器。

触发远程构建(例如,使用脚本): 该选项会提供一个接口,可以用来在代码层面触发构建。这里不做介绍,后期可能会用到。
Build after other projects are built: 该选项意思是”在其他projects构建后构建”。这里不作介绍,后期可能会用到该选项。
Build periodically: 周期性的构建。很好理解,就是每隔一段时间进行构建。日程表类似linux crontab书写格式。如下图的设置,表示每隔30分钟进行一次构建。

Build when a change is pushed to GitLab:当有更改push到gitlab代码仓库,即触发构建。后面会有一个触发构建的地址,一般被称为webhooks。需要将这个地址配置到gitlab中,webhooks如何配置后面介绍。这个是常用的构建触发器。
Poll SCM:该选项是配合上面这个选项使用的。当代码仓库发生改动,jenkins并不知道。需要配置这个选项,周期性的去检查代码仓库是否发生改动。

4.构建环境

构建环境就是构建之前的一些准备工作,如指定构建工具(在这里我使用ant)。

With Ant:选择这个工具,并指定ant版本和jdk版本。这两个工具的版本我都事先在服务器上安装,并且在jenkins全局工具中配置好了。其他选项不作介绍,同样可以查看”帮助信息” 获得使用帮助。

5.构建

选择下方的增加构建步骤。

可以选择的项很多。这里就介绍”Invoke Ant” 和”Execute shell”.
Eexcute shell: 执行shell命令,该工具是针对linux环境的,windows环境也有对应的工具”Execute Windows batch command”。 在构建之前,可能我们需要执行一些命令,比如压缩包的解压之类的。为了演示,我就简单的执行  “echo $RANDOM” 这样的linux shell下生产随机数命令。
Invoke Ant:Ant是一款java项目构建工具,当然也能用来构建php。

Ant Version: 选择Ant版本。这个ant版本是安装在jenkins服务器上的版本,并且需要在jenkins”系统工具”中设置好。
Targets:要执行的操作,一行一个操作任务。以上图为例,build是构建,tar是打包。
Build File: 是Ant构建的配置文件,如果不指定,则是在项目路径下的workspace目录中的build.xml。build.xml文件具体怎么配置,后面再细讲。properties: 设定一些变量,这些变量可以在build.xml 中被引用。
Send files or execute commands over SSH:发送文件到远程主机或执行命令(脚本)

Name: SSH Server的名称。SSH Server可以在jenkins-系统设置中配置。Source files: 需要发送给远程主机的源文件。
Remove prefix: 移除前面的路径。如果不设置这个参数,则远程主机会自动创建构建源 source files 包含的那个路径。
Remote directory: 远程主机目录。
Exec command:在远程主机上执行的命令,或者执行的脚本。

6.构建后操作

构建后操作,就是对project构建完成后的一些后续操作,比如生成相应的代码测试报告。

Publish Clover PHP Coverage Report:发布代码覆盖率xml格式的文件报告。路径会在”build.xml”文件中定义
Publish HTML reports:发布代码覆盖率的HTML报告。  
Report Crap: 发布crap报告
E-mail Notification:  邮件通知,构建完成后发邮件到指定的邮箱。
以上配置完成后,点击保存。

7.其他相关配置

 SSH Server配置登录jenkins — 系统管理 — 系统设置配置请看下图

SSH Servers: 由于jenkins服务器公钥文件我已经配置好,所以之后新增SSH Servers 只需要配置这一项即可。 
Name: 自定义,需要全局唯一。
HostName: 主机名,直接用ip地址即可。
Username: 新增Server的用户名,这里配置的是root。
Remote Directory: 远程目录。jenkins服务器发送文件给新增的server默认是在这个目录。

Ant 配置文件 “build.xml”

接下来讲解Ant 构建配置文件”build.xml”。 之所以是build.xml 这是因为官方惯例。就好比任何编程语言的入门都会是打印”Hello world”.  你也可以用其他名称代替”build.xml” .下面针对配置文件”build.xml” 关键配置进行说明。

project name就是项目名称,和jenkins所创建的对应。
target name=”build” 就是构建的名称,和jenkins构建步骤 那里的targets对应。
depends指明构建需要进行的一些操作。
property 用来设置变量。
fileset 这一行指明了一个文件夹,用include来指明需要包含的文件,exclude指明不包含的文件,”tar”即是打包这个文件夹中匹配到的文件。下面的这些target都是一些实际的操作步骤,比如make_runtime这个”target” 就是创建了一些目录。phpcs就是利用PHP_CodeSniffer这个工具 对PHP代码规范与质量检查工具。

最后这个target “tar” 就是打包文件。因为上面的build 并没有包含这个target,所以默认情况下,执行build是不会打包文件的,所以在jenkins project配置界面,Ant构建那一步的targets,我们才会有”build” 和 “tar” 这两个targets。如果build.xml 中 “build”这个target depends中已经包含”tar” , 就不需要在jenkins中增加”tar”了。其他一些target 都是利用一些工具对php代码的操作,比如phpunit是进行php单元测试。这一些方面我没有深入的研究,只是进行了一些简单的配置,毕竟不是这方面的专业人士。

四、进行jenkins project 构建

第一次配置好jenkins project之后,会自动触发一次构建。此后,每当有commit 提交到master分支(前面设置的是master分支,也可以设置为其他分支),就会触发一次构建。当然也可以在project页面手动触发构建。点击左边的”立即构建” 手动触发构建。

五、构建结果说明

构建状态

Successful蓝色:构建完成,并且被认为是稳定的。
Unstable黄色:构建完成,但被认为是不稳定的。
Failed红色:构建失败。
Disable灰色:构建已禁用

构建稳定性

构建稳定性用天气表示:晴、晴转多云、多云、小雨、雷阵雨。天气越好表示构建越稳定,反之亦然

构建历史界面

 Console output: 输出构建的日志信息