
1、7年+测试经险,其中5年+金融(银行)领域业务经验,丰富的app\web\服务端测试经验. 2、4+年管理经验,有多次从0组建测试团队的经历,最多带过20+人的测试团队。
管理是可以通过后天的学习掌握的一项技能,但同时管理这条路每个人走的都不一样,因为没有一个固定的标准而且前面的路有很多未知和不确定性,所以不同的人对管理的理解、定义以及怎么做管理都会有不同的想法、做法。 很多一线的技术人员通常都不太愿意转管理,原因有很多,比如痴迷技术,对管理不感冒,也有不知道如何做管理,觉得做管理后很空虚,没有成就感等等。这些问题其实在我最初从技术转向管理时都在相当长一段时间内困扰着我,不过随着这两年自己在管理上的不断学习、实践、再学习、再实践,总的来说进步还是比较明显。本文会从以下几个方面进行总结与介绍初为管理者时如果进行角色转换、如何调整自己心态等等: 一、愿意重视: 从宏观角度来看,技术通常意味着从0->1,而管理则是1->100,比如一提到智能机,首先想到的是乔布斯的iphone,他具有划时代的意义。随后又出现在android等其它智能机,到现在智能机已经是随处可见并且手机的功能、性能都在不断变得更强。但这些始终在技术上没有特别大的变革,还是属于智能机,这就是从1->100。而且现在要做一个智能机好像也不是什么难事,市面上各家厂商都可以自己做手机。总结来就是:技术只有商业化才改变社会,技术可以借(买),管理靠自己,技术先敲门、管理定天下,技术只有在管理下才能成功。 当然,上面说的层面比较高,对于一线技术人员来说还接触不到,但是我们要意识到从心里愿意去重视管理,就是好的开始了。 二、愿意转换 1、是什么阻碍了我们转换角色? 没有真正重视: 是否重视可以从自己每天的时间分配比例看出来,因为管理是需要花时间去学习、实践。 没有挑战惯性: 挑战舒适区,实践中迭代,挑战思维,挑战沟通。 管理这条路每个人走的都不一样,也没有一个固定的标准,前面的路有很多未知和不确定性,需要随时准备好迎接这些挑战。 没有有效指引: 这个就是不知道怎么转,不知道要做什么,不知道怎么做。 2、有哪些角色需要转换,我们看下技术人才与管理人才的异同: 再来看一下我们要从哪些方面进行角色转换,主要包括5个方面: 管人与管事两手抓:让人开心的把事做好 放下成就感:延长自己的成就感,同时注重团队成员的成就感。 责任担当: 要将例外的事件例行化、流程化,不要总是忙着救火与搞突击。 同时,又要懂得变通,处理突发事件,管理制度以外。 领导的7T 领导的7S 总结一下: 变依靠个人力量为依靠集体力量,从追求个人成功到追求团队成功 不仅要自己做好事,还要保证别人也做好事,管理比单纯做技术更需要全局性 从单一角色、专一工作要面对处理很多事情,走向管理岗位是一对多的转变、工作对象从事到人的转变,需要沟通与领导技能 做工作除了计划性,更要控制性与跟踪性 要学会沟通,与人打交道,激发人的动力,既要关心技术,又要关心人,所以要多付出 事情不仅自己做好了就行了,而是要带领大家把本部门的事情做完才行,需要的是集体主义而不是信人主义 从管事转变到管事、管人,从自己做事转变到组织、协调大家共同做事。 三、敢于要求 初为管理者时常常会有很多担忧,比如不好意思要求,觉得革命要靠自觉,又或者担心要求了对方会不接受会拒绝等等,这些都会严重阻碍我们的工作开展与目标的达成。正所谓无私让人无畏,才能敢于要求。思想包袱不要太重,统一团队的目标,并打造适合自己团队的文化和氛围,使整个团队为共同的目标努力。 四、敢于反馈 有了目标,敢于要求,接着有了执行,就会产生结果,这个结果包括过程结果和实际结果。针对结果做为管理都也需要及时给出反馈,而且反馈也需要有相当的技巧。 五、善于沟通 沟通也是做为一个管理者非常重要的技能,如果无法做好沟通,一切工作的开展都会受到阻碍: 六、善于识人 识人方面是个比较难掌握的东西,需要读些心理学和哲学的书以触类旁通,此处不做介绍。 七、善于激励 管理是一条不归路,只有不断学习、实践、总结学习、在实践,才能不断提高自己的管理水平和修养。
一、折线图: # -*- coding:utf-8 -*- import xlsxwriter # 创建一个excel workbook = xlsxwriter.Workbook("chart_line.xlsx") # 创建一个sheet worksheet = workbook.add_worksheet() # worksheet = workbook.add_worksheet("bug_analysis") # 自定义样式,加粗 bold = workbook.add_format({'bold': 1}) # --------1、准备数据并写入excel--------------- # 向excel中写入数据,建立图标时要用到 headings = ['Number', 'testA', 'testB'] data = [ ['2017-9-1', '2017-9-2', '2017-9-3', '2017-9-4', '2017-9-5', '2017-9-6'], [10, 40, 50, 20, 10, 50], [30, 60, 70, 50, 40, 30], ] # 写入表头 worksheet.write_row('A1', headings, bold) # 写入数据 worksheet.write_column('A2', data[0]) worksheet.write_column('B2', data[1]) worksheet.write_column('C2', data[2]) # --------2、生成图表并插入到excel--------------- # 创建一个柱状图(line chart) chart_col = workbook.add_chart({'type': 'line'}) # 配置第一个系列数据 chart_col.add_series({ # 这里的sheet1是默认的值,因为我们在新建sheet时没有指定sheet名 # 如果我们新建sheet时设置了sheet名,这里就要设置成相应的值 'name': '=Sheet1!$B$1', 'categories': '=Sheet1!$A$2:$A$7', 'values': '=Sheet1!$B$2:$B$7', 'line': {'color': 'red'}, }) # 配置第二个系列数据 chart_col.add_series({ 'name': '=Sheet1!$C$1', 'categories': '=Sheet1!$A$2:$A$7', 'values': '=Sheet1!$C$2:$C$7', 'line': {'color': 'yellow'}, }) # 配置第二个系列数据(用了另一种语法) # chart_col.add_series({ # 'name': ['Sheet1', 0, 2], # 'categories': ['Sheet1', 1, 0, 6, 0], # 'values': ['Sheet1', 1, 2, 6, 2], # 'line': {'color': 'yellow'}, # }) # 设置图表的title 和 x,y轴信息 chart_col.set_title({'name': 'The xxx site Bug Analysis'}) chart_col.set_x_axis({'name': 'Test number'}) chart_col.set_y_axis({'name': 'Sample length (mm)'}) # 设置图表的风格 chart_col.set_style(1) # 把图表插入到worksheet并设置偏移 worksheet.insert_chart('A10', chart_col, {'x_offset': 25, 'y_offset': 10}) workbook.close() 效果图: 二、柱状图: # -*- coding:utf-8 -*- import xlsxwriter # 创建一个excel workbook = xlsxwriter.Workbook("chart_column.xlsx") # 创建一个sheet worksheet = workbook.add_worksheet() # worksheet = workbook.add_worksheet("bug_analysis") # 自定义样式,加粗 bold = workbook.add_format({'bold': 1}) # --------1、准备数据并写入excel--------------- # 向excel中写入数据,建立图标时要用到 headings = ['Number', 'testA', 'testB'] data = [ ['2017-9-1', '2017-9-2', '2017-9-3', '2017-9-4', '2017-9-5', '2017-9-6'], [10, 40, 50, 20, 10, 50], [30, 60, 70, 50, 40, 30], ] # 写入表头 worksheet.write_row('A1', headings, bold) # 写入数据 worksheet.write_column('A2', data[0]) worksheet.write_column('B2', data[1]) worksheet.write_column('C2', data[2]) # --------2、生成图表并插入到excel--------------- # 创建一个柱状图(column chart) chart_col = workbook.add_chart({'type': 'column'}) # 配置第一个系列数据 chart_col.add_series({ # 这里的sheet1是默认的值,因为我们在新建sheet时没有指定sheet名 # 如果我们新建sheet时设置了sheet名,这里就要设置成相应的值 'name': '=Sheet1!$B$1', 'categories': '=Sheet1!$A$2:$A$7', 'values': '=Sheet1!$B$2:$B$7', 'line': {'color': 'red'}, }) # 配置第二个系列数据(用了另一种语法) chart_col.add_series({ 'name': '=Sheet1!$C$1', 'categories': '=Sheet1!$A$2:$A$7', 'values': '=Sheet1!$C$2:$C$7', 'line': {'color': 'yellow'}, }) # 配置第二个系列数据(用了另一种语法) # chart_col.add_series({ # 'name': ['Sheet1', 0, 2], # 'categories': ['Sheet1', 1, 0, 6, 0], # 'values': ['Sheet1', 1, 2, 6, 2], # 'line': {'color': 'yellow'}, # }) # 设置图表的title 和 x,y轴信息 chart_col.set_title({'name': 'The xxx site Bug Analysis'}) chart_col.set_x_axis({'name': 'Test number'}) chart_col.set_y_axis({'name': 'Sample length (mm)'}) # 设置图表的风格 chart_col.set_style(1) # 把图表插入到worksheet以及偏移 worksheet.insert_chart('A10', chart_col, {'x_offset': 25, 'y_offset': 10}) workbook.close() 效果图: PS: 其实前面两个图只变动一点:把 line 个性为 column chart_col = workbook.add_chart({'type': 'column'}) 三、饼图: # -*- coding:utf-8 -*- import xlsxwriter # 创建一个excel workbook = xlsxwriter.Workbook("chart_pie.xlsx") # 创建一个sheet worksheet = workbook.add_worksheet() # 自定义样式,加粗 bold = workbook.add_format({'bold': 1}) # --------1、准备数据并写入excel--------------- # 向excel中写入数据,建立图标时要用到 data = [ ['closed', 'active', 'reopen', 'NT'], [1012, 109, 123, 131], ] # 写入数据 worksheet.write_row('A1', data[0], bold) worksheet.write_row('A2', data[1]) # --------2、生成图表并插入到excel--------------- # 创建一个柱状图(pie chart) chart_col = workbook.add_chart({'type': 'pie'}) # 配置第一个系列数据 chart_col.add_series({ 'name': 'Bug Analysis', 'categories': '=Sheet1!$A$1:$D$1', 'values': '=Sheet1!$A$2:$D$2', 'points': [ {'fill': {'color': '#00CD00'}}, {'fill': {'color': 'red'}}, {'fill': {'color': 'yellow'}}, {'fill': {'color': 'gray'}}, ], }) # 设置图表的title 和 x,y轴信息 chart_col.set_title({'name': 'Bug Analysis'}) # 设置图表的风格 chart_col.set_style(10) # 把图表插入到worksheet以及偏移 worksheet.insert_chart('B10', chart_col, {'x_offset': 25, 'y_offset': 10}) workbook.close() 效果图: 参考资料: http://xlsxwriter.readthedocs.io/chart_examples.html http://xlsxwriter.readthedocs.io/chart.html
一、安装xlrd模块: 1、mac下打开终端输入命令: pip install XlsxWriter 2、验证安装是否成功: 在mac终端输入 python 进入python环境 然后输入 import xlswriter 不报错说明模块安装成功 二、常用方法: 1、创建excel文件 # 创建文件 workbook = xlsxwriter.Workbook("new_excel.xlsx") 2、创建sheet # 创建sheet worksheet = workbook.add_worksheet("first_sheet") 3、特定单元格里写入数据 a) 写入文本 # 法一: worksheet.write('A1', 'write something') # 法二: worksheet.write(1, 0, 'hello world') b)写入数字 # 写入数字 worksheet.write(0, 1, 32) worksheet.write(1, 1, 32.3) c)写入函数 worksheet.write(2, 1, '=sum(B1:B2)') d)写入图片 # 插入图片 worksheet.insert_image(0, 5, 'test.png') worksheet.insert_image(0, 5, 'test.png', {'url': 'http://httpbin.org/'}) e)写入日期: # 写入日期 d = workbook.add_format({'num_format': 'yyyy-mm-dd'}) worksheet.write(0, 2, datetime.datetime.strptime('2017-09-13', '%Y-%m-%d'), d) f)设置行、列属性 # 设置行属性,行高设置为40 worksheet.set_row(0, 40) # 设置列属性,把A到B列宽设置为20 worksheet.set_column('A:B', 20) 4、自定义格式: 常用格式: 字体颜色:color 字体加粗:bold 字体大小:font_site 日期格式:num_format 超链接:url 下划线设置:underline 单元格颜色:bg_color 边框:border 对齐方式:align # 自定义格式 f = workbook.add_format({'border': 1, 'font_size': 13, 'bold': True, 'align': 'center','bg_color': 'cccccc'}) worksheet.write('A3', "python excel", f) worksheet.set_row(0, 40, f) worksheet.set_column('A:E', 20, f) 5、批量往单元格写入数据 # 批量往单元格写入数据 worksheet.write_column('A15', [1, 2, 3, 4, 5]) # 列写入,从A15开始 worksheet.write_row('A12', [6, 7, 8, 9]) # 行写入,从A12开始 6、合并单元格写入 # 合并单元格写入 worksheet.merge_range(7,5, 11, 8, 'merge_range') 7、关闭文件 workbook.close() 8、生成图表: xlswriter还可以用来生成图表,这一部分内容也比较多,下一节单独介绍。 示例: # -*- coding:utf-8 -*- import xlsxwriter workbook = xlsxwriter.Workbook("data.xlsx") worksheet = workbook.add_worksheet() data = ( ['kobe', 5000], ['T-Mac', 3000], ['Jordan', 6000], ['James', 5000], ) f = workbook.add_format({'bold': True, 'bg_color': 'yellow'}) worksheet.write(0, 0, 'name', f) worksheet.write(0, 1, 'price', f) row = 1 col = 0 for item, cost in data: worksheet.write(row, col, item) worksheet.write(row, col+1, cost) row += 1 workbook.close() 参考官网:http://xlsxwriter.readthedocs.io/
一、安装xlrd模块: 1、mac下打开终端输入命令: pip install xlrd 2、验证安装是否成功: 在mac终端输入 python 进入python环境 然后输入 import xlrd 不报错说明模块安装成功 二、常用方法: 1、导入模块: import xlrd 2、打开文件: x1 = xlrd.open_workbook("data.xlsx") 3、获取sheet: 获取所有sheet名字:x1.sheet_names() 获取sheet数量:x1.nsheets 获取所有sheet对象:x1.sheets() 通过sheet名查找:x1.sheet_by_name("test”) 通过索引查找:x1.sheet_by_index(3) # -*- coding:utf-8 -*- import xlrd import os filename = "demo.xlsx" filePath = os.path.join(os.getcwd(), filename) print filePath # 1、打开文件 x1 = xlrd.open_workbook(filePath) # 2、获取sheet对象 print 'sheet_names:', x1.sheet_names() # 获取所有sheet名字 print 'sheet_number:', x1.nsheets # 获取sheet数量 print 'sheet_object:', x1.sheets() # 获取所有sheet对象 print 'By_name:', x1.sheet_by_name("test") # 通过sheet名查找 print 'By_index:', x1.sheet_by_index(3) # 通过索引查找 输出: sheet_names: [u' plan', u'team building', u'modile', u'test'] sheet_number: 4 sheet_object: [<xlrd.sheet.Sheet object at 0x10244c190>, <xlrd.sheet.Sheet object at 0x10244c150>, <xlrd.sheet.Sheet object at 0x10244c110>, <xlrd.sheet.Sheet object at 0x10244c290>] By_name: <xlrd.sheet.Sheet object at 0x10244c290> By_index: <xlrd.sheet.Sheet object at 0x10244c290> 4、获取sheet的汇总数据: 获取sheet名:sheet1.name 获取总行数:sheet1.nrows 获取总列数:sheet1.ncols # -*- coding:utf-8 -*- import xlrd import os from datetime import date,datetime filename = "demo.xlsx" filePath = os.path.join(os.getcwd(), filename) print filePath # 打开文件 x1 = xlrd.open_workbook(filePath) # 获取sheet的汇总数据 sheet1 = x1.sheet_by_name("plan") print "sheet name:", sheet1.name # get sheet name print "row num:", sheet1.nrows # get sheet all rows number print "col num:", sheet1.ncols # get sheet all columns number 输出: sheet name: plan row num: 31 col num: 11 5、单元格批量读取: a)行操作: sheet1.row_values(0) # 获取第一行所有内容,合并单元格,首行显示值,其它为空。 sheet1.row(0) # 获取单元格值类型和内容 sheet1.row_types(0) # 获取单元格数据类型 # -*- coding:utf-8 -*- import xlrd import os from datetime import date,datetime filename = "demo.xlsx" filePath = os.path.join(os.getcwd(), filename) x1 = xlrd.open_workbook(filePath) sheet1 = x1.sheet_by_name("plan") # 单元格批量读取 print sheet1.row_values(0) # 获取第一行所有内容,合并单元格,首行显示值,其它为空。 print sheet1.row(0) # 获取单元格值类型和内容 print sheet1.row_types(0) # 获取单元格数据类型 输出: [u'learning plan', u'', u'', u'', u'', u'', u'', u'', 123.0, 42916.0, 0] [text:u'learning plan', empty:u'', empty:u'', empty:u'', empty:u'', empty:u'', empty:u'', empty:u'', number:123.0, xldate:42916.0, bool:0] array('B', [1, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4]) b) 表操作 sheet1.row_values(0, 6, 10) # 取第1行,第6~10列(不含第10表) sheet1.col_values(0, 0, 5) # 取第1列,第0~5行(不含第5行) sheet1.row_slice(2, 0, 2) # 获取单元格值类型和内容 sheet1.row_types(1, 0, 2) # 获取单元格数据类型 # -*- coding:utf-8 -*- import xlrd import os from datetime import date,datetime filename = "demo.xlsx" filePath = os.path.join(os.getcwd(), filename) print filePath # 1、打开文件 x1 = xlrd.open_workbook(filePath) sheet1 = x1.sheet_by_name("plan") # 列操作 print sheet1.row_values(0, 6, 10) # 取第1行,第6~10列(不含第10表) print sheet1.col_values(0, 0, 5) # 取第1列,第0~5行(不含第5行) print sheet1.row_slice(2, 0, 2) # 获取单元格值类型和内容,同sheet1.row(0) print sheet1.row_types(1, 0, 2) # 获取单元格数据类型 输出: [u'', u'', 123.0, 42916.0] [u'learning plan', u'\u7f16\u53f7', 1.0, 2.0, 3.0] [number:1.0, text:u'\u7ba1\u7406\u5b66\u4e60'] array('B', [1, 1]) 6、特定单元格读取: a) 获取单元格值: sheet1.cell_value(1, 2) sheet1.cell(1, 2).value sheet1.row(1)[2].value b) 获取单元格类型: sheet1.cell(1, 2).ctype sheet1.cell_type(1, 2) sheet1.row(1)[2].ctype # -*- coding:utf-8 -*- import xlrd import os from datetime import date,datetime filename = "demo.xlsx" filePath = os.path.join(os.getcwd(), filename) x1 = xlrd.open_workbook(filePath) sheet1 = x1.sheet_by_name("plan") # 特定单元格读取 # 取值 print sheet1.cell_value(1, 2) print sheet1.cell(1, 2).value print sheet1.row(1)[2].value #取类型 print sheet1.cell(1, 2).ctype print sheet1.cell_type(1, 2) print sheet1.row(1)[2].ctype 7、(0,0)转换A1: xlrd.cellname(0, 0) # (0,0)转换成A1 xlrd.cellnameabs(0, 0) # (0,0)转换成$A$1 xlrd.colname(30) # 把列由数字转换为字母表示 # -*- coding:utf-8 -*- import xlrd import os filename = "demo.xlsx" filePath = os.path.join(os.getcwd(), filename) # 打开文件 x1 = xlrd.open_workbook(filePath) sheet1 = x1.sheet_by_name("plan") # (0,0)转换成A1 print xlrd.cellname(0, 0) # (0,0)转换成A1 print xlrd.cellnameabs(0, 0) # (0,0)转换成$A$1 print xlrd.colname(30) # 把列由数字转换为字母表示 输出: A1 $A$1 AE 8、数据类型: 空:0 字符串:1 数字:2 日期:3 布尔:4 error:5
用例的管理问题解决了后,接下来要考虑的就是报告我问题了,这里生成测试报告主要用到 HTMLTestRunner.py 这个模块,下面简单介绍一下如何使用: 一、下载HTMLTestRunner下载: 这个模块不能通过pip安装,只能下载安装,下载地址如下: python2.x版本:http://tungwaiyip.info/software/HTMLTestRunner.html python3.x版本:http://hzqldjb.blog.51cto.com/9587820/1590802 二、mac下配置: 1、终端进入python环境 2、输入: import sys print sys.path 3、找到site-packages文件夹的路径并将下载的 HTMLTestRunner.py 文件拷贝到此的文件夹下 4、在python环境下,输入 import HTMLTestRunner 不报错即安装成功 三、使用该模块生成报告: 1、目录结构 case包下面有baidu,httpbin两个包 每个包下面分别有两个测试的py文件 每个test_00x.py文件里各有2个test case run_all_case.py文件:用来执行所有的test case且生成测试报告 2、运行后生成报告如下: 3、run_all_case.py代码如下: # -*- coding:utf-8 -*- import unittest import os import time import HTMLTestRunner # 用例路径 case_path = os.path.join(os.getcwd()) # 报告存放路径 report_path = os.path.join(os.getcwd(), 'report') print report_path def all_case(): discover = unittest.defaultTestLoader.discover(case_path, pattern="test*.py", top_level_dir=None) print discover return discover if __name__ == '__main__': # 1、获取当前时间,这样便于下面的使用。 now = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime(time.time())) # 2、html报告文件路径 report_abspath = os.path.join(report_path, "result_"+now+".html") # 3、打开一个文件,将result写入此file中 fp = open(report_abspath, "wb") runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=u'接口自动化测试报告,测试结果如下:', description=u'用例执行情况:') # 4、调用add_case函数返回值 runner.run(all_case()) fp.close()
前面五节主要介绍了环境搭建和requests库的使用,可以使用这些进行接口请求的发送。但是如何管理接口案例?返回结果如何自动校验?这些内容光靠上面五节是不行的,因此从本节开始我们引入python单元测试框架 unittest,用它来处理批量用例管理,校验返回结果,初始化工作以及测试完成后的环境复原工作等等。 一、单个用例管理起来比较简单,参考如下图,单个用例一般多用在调试的时候: 二、代码如下: # -*- coding:utf-8 -*- # 单个用例执行 # 1、导入模块 import unittest # 2、继承自unittest.TestCase类 class TestOne(unittest.TestCase): # 3、配置环境:进行测试前的初始化工作 def setUp(self): print '\ncases before' pass # 4、定义测试用例,名字以“test”开头 def test_add(self): '''test add method''' print 'add...' a = 3 + 4 b = 7 # 5、定义assert断言,判断测试结果 self.assertEqual(a, b) def test_sub(self): '''test sub method''' print 'sub...' a = 10 - 5 b = 4 self.assertEqual(a, b) # 6、清理环境 def tearDown(self): print 'case after' pass # 7、该方法会搜索该模块下所有以test开头的测试用例方法,并自动执行它们 if __name__ == '__main__': unittest.main() 输出: Ran 2 tests in 0.001s OK cases before add... case after cases before sub... case after Process finished with exit code 0
我们日常项目中的接口测试案例肯定不止一个,当案例越来越多时我们如何管理这些批量案例?如何保证案例不重复?如果案例非常多(成百上千,甚至更多)时如何保证案例执行的效率?如何做(批量)测试数据的管理?如何做到数据与脚本分离? 以上这些问题才是我们自动化测试中要重点考虑的问题,单个用例其实并不难。 来看一下在unittest框架中如何管理批量案例: 一、手工加载批量用例: # -*- coding:utf-8 -*- # 批量用例执行--手工加载 import unittest class TestOne(unittest.TestCase): def setUp(self): print '\ncases before' pass def test_add(self): '''test add method''' print 'add...' a = 3 + 4 b = 7 self.assertEqual(a, b) def test_sub(self): '''test sub method''' print 'sub...' a = 10 - 5 b = 5 self.assertEqual(a, b) def tearDown(self): print 'case after' pass if __name__ == '__main__': # 1、构造用例集 suite = unittest.TestSuite() # 2、执行顺序是安加载顺序:先执行test_sub,再执行test_add suite.addTest(TestOne("test_sub")) suite.addTest(TestOne("test_add")) # 3、实例化runner类 runner = unittest.TextTestRunner()# 4、执行测试 runner.run(suite) 二、自动加载批量用例: # -*- coding:utf-8 -*- # 批量用例执行--自动加载 import unittest import os class TestOne(unittest.TestCase): def setUp(self): print '\ncases before' pass def test_add(self): '''test add method''' print 'add...' a = 3 + 4 b = 7 self.assertEqual(a, b) def test_sub(self): '''test sub method''' print 'sub...' a = 10 - 5 b = 5 self.assertEqual(a, b) def tearDown(self): print 'case after' pass if __name__ == '__main__': # 1、设置待执行用例的目录 test_dir = os.path.join(os.getcwd()) # 2、自动搜索指定目录下的cas,构造测试集,执行顺序是命名顺序:先执行test_add,再执行test_sub discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py') # 实例化TextTestRunner类 runner = unittest.TextTestRunner() # 使用run()方法运行测试套件(即运行测试套件中的所有用例) runner.run(discover) 以上只是解决了如何管理批量案例的问题,其它的问题如何做(批量)测试数据的管理?如何做到数据与脚本分离?后续在介绍。
有了前面几节的介绍,基本的接口测试是可以满足了。本节一些其它的高级技巧: 一、认证 1、基本认证: # -*- coding:utf-8 -*- import requests url = "http://httpbin.org/basic-auth/user/passwd" r1 = requests.get(url) print "未提供用户名密码:" + str(r1.status_code) #Basic Authentication r2 = requests.get(url,auth=('user','passwd')) print "已提供用户名密码:" + str(r2.status_code) 输出: 未提供用户名密码:401 已提供用户名密码:200 2、数字认证: >>> from requests.auth import HTTPDigestAuth >>> url = 'http://httpbin.org/digest-auth/auth/user/pass' >>> requests.get(url, auth=HTTPDigestAuth('user', 'pass')) <Response [200]> 3、OAuth认证 暂略。可参考官方文档:http://docs.python-requests.org/en/master/user/authentication/ 二、代理 1、方法一:proxy参数: import requests proxies = { "https": "http://41.118.132.69:4433" } r = requests.post("http://httpbin.org/post", proxies=proxies) print r.text 2、方法二:设置环境变量: $ export HTTP_PROXY="http://10.10.1.10:3128" $ export HTTPS_PROXY="http://10.10.1.10:1080" $ python >>> import requests >>> requests.get('http://example.org') 3、HTTP Basic Auth使用代理方法:http://user:password@host/ proxies = {'http': 'http://user:pass@10.10.1.10:3128/'} 三、证书验证 1、SSL证书(HTTPS): import requests #跳过12306 的证书验证,把 verify 设置为 False: r = requests.get('https://kyfw.12306.cn/otn/', verify=False) print r.text 2、客户端证书: >>> requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key')) <Response [200]> or s = requests.Session() s.cert = '/path/client.cert' 四、超时配置 1 、利用timeout参数来配置最大请求时间: r = requests.get('https://github.com', timeout=5) 2、设置timeout=None,告诉请求永远等待响应,而不将请求作为超时值传递 r = requests.get('https://github.com', timeout=None) 五、错误异常: 1、所有Requests显式抛出的异常都继承自:requests.exctptions.RequestException 2、遇到网络问题(如:DNS查询失败,拒绝连接等)时,requests会抛出一个 ConnectionError 异常 3、遇到罕见的无效HTTP响应时,Request则会抛出一个 HTTPError 异常 4、若请求超时,则抛出一个 Timeout 异常 5、若请求超过了最大的重写向次数,则会抛出一个 TooManyRedirects 异常
掌握了前面几节的的内容,就可以做一些简单的http协议接口的请求发送了,但是这些还不够。HTTP协议是一个无状态的应用层协议,也就是说前后两次请求是没有任何关系的,那如果我们测试的接口之前有相互依赖关系怎么办呢(比如我要在博客园发文章,是需要先登录的),这时我们就要用到cookie和session技术来保持客户端与服务器端连接的状态,这也就是本节要介绍的内容: 一、Cookie: 1、获取cookie: # -*- coding:utf-8 -*- #获取cookie import requests import json url = "https://www.baidu.com/" r = requests.get(url) #将RequestsCookieJar转换成字典 c = requests.utils.dict_from_cookiejar(r.cookies) print r.cookies print c for a in r.cookies: print a.name,a.value 输出: <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]> {'BDORZ': '27315'} BDORZ 27315 二、发送cookie: # -*- coding:utf-8 -*- #发送cookie到服务器 import requests import json host = "http://httpbin.org/" endpoint = "cookies" url = ''.join([host,endpoint]) #方法一:简单发送 # cookies = {"aaa":"bbb"} # r = requests.get(url,cookies=cookies) # print r.text #方法二:复杂发送 s = requests.session() c = requests.cookies.RequestsCookieJar() c.set('c-name','c-value',path='/xxx/uuu',domain='.test.com') s.cookies.update(c) 二、Session 1、保持会话同步: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "cookies" url = ''.join([host,endpoint]) url1 = "http://httpbin.org/cookies/set/sessioncookie/123456789" r = requests.get(url) print r.textprint "------" s = requests.session() #初始化一个session对象 s.get(url1) #cookie的信息存在了session中 r = s.get(url) print r.text 输出: { "cookies": {} } ------ { "cookies": { "sessioncookie": "123456789" } } 2、保存会话信息: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "headers" url = ''.join([host,endpoint]) header1 = {"testA":"AAA"} header2 = {"testB":"BBB"} s = requests.session() #初始化一个session对象 s.headers.update(header1) #已经存在于服务中的信息 r = s.get(url,headers=header2) #发送新的信息 print r.text 输出: { "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org", "Testa": "AAA", "Testb": "BBB", "User-Agent": "python-requests/2.18.1" } } 3、删除已存在的会话信息,保存为None # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "headers" url = ''.join([host,endpoint]) header1 = {"testA":"AAA"} header2 = {"testB":"BBB"} s = requests.session() #初始化一个session对象 s.headers.update(header1) #已经存在于服务中的信息 r = s.get(url,headers=header2) #发送新的信息 print r.text print '--------' s.headers['testA'] = None #删除会话里的信息testA r1 = s.get(url,headers = header2) print r1.text { "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org", "Testa": "AAA", "Testb": "BBB", "User-Agent": "python-requests/2.18.1" } } -------- { "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Host": "httpbin.org", "Testb": "BBB", "User-Agent": "python-requests/2.18.1" } } 4、提供默认数据: s = requests.Session() s.auth = ('user', 'pass') s.headers.update({'x-test': 'true'}) # both 'x-test' and 'x-test2' are sent s.get('http://httpbin.org/headers', headers={'x-test2': 'true'}) 参考: http://docs.python-requests.org/en/master/user/quickstart/#cookies http://docs.python-requests.org/en/master/user/advanced/#session-objects
上一节介绍了 requests.get() 方法的基本使用,本节介绍 requests.post() 方法的使用: 本文目录: 一、方法定义 二、post方法简单使用 1、带数据的post 2、带header的post 3、带json的post 4、带参数的post 5、普通文件上传 6、定制化文件上传 7、多文件上传 一、方法定义: 1、到官方文档去了下requests.post()方法的定义,如下: 2、源码: 3、常用返回信息: 二、post方法简单使用: 1、带数据的post: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "post" url = ''.join([host,endpoint]) data = {'key1':'value1','key2':'value2'} r = requests.post(url,data=data) #response = r.json() print (r.text) 输出: { "args": {}, "data": "", "files": {}, "form": { "key1": "value1", "key2": "value2" }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Content-Length": "23", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "python-requests/2.18.1" }, "json": null, "origin": "183.14.133.88", "url": "http://httpbin.org/post" } 2、带header的post: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "post" url = ''.join([host,endpoint]) headers = {"User-Agent":"test request headers"} # r = requests.post(url) r = requests.post(url,headers=headers) #response = r.json() 输出: { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Content-Length": "0", "Host": "httpbin.org", "User-Agent": "test request headers" }, "json": null, "origin": "183.14.133.88", "url": "http://httpbin.org/post" } 3、带json的post: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "post" url = ''.join([host,endpoint]) data = { "sites": [ { "name":"test" , "url":"www.test.com" }, { "name":"google" , "url":"www.google.com" }, { "name":"weibo" , "url":"www.weibo.com" } ] } r = requests.post(url,json=data) # r = requests.post(url,data=json.dumps(data)) response = r.json() 输出: { "args": {}, "data": "{\"sites\": [{\"url\": \"www.test.com\", \"name\": \"test\"}, {\"url\": \"www.google.com\", \"name\": \"google\"}, {\"url\": \"www.weibo.com\", \"name\": \"weibo\"}]}", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Content-Length": "140", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "python-requests/2.18.1" }, "json": { "sites": [ { "name": "test", "url": "www.test.com" }, { "name": "google", "url": "www.google.com" }, { "name": "weibo", "url": "www.weibo.com" } ] }, "origin": "183.14.133.88", "url": "http://httpbin.org/post" } 4、带参数的post: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "post" url = ''.join([host,endpoint]) params = {'key1':'params1','key2':'params2'} # r = requests.post(url) r = requests.post(url,params=params) #response = r.json() print (r.text) 输出: { "args": { "key1": "params1", "key2": "params2" }, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Content-Length": "0", "Host": "httpbin.org", "User-Agent": "python-requests/2.18.1" }, "json": null, "origin": "183.14.133.88", "url": "http://httpbin.org/post?key2=params2&key1=params1" } 5、普通文件上传: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "post" url = ''.join([host,endpoint]) #普通上传 files = { 'file':open('test.txt','rb') } r = requests.post(url,files=files) print (r.text) 输出: { "args": {}, "data": "", "files": { "file": "hello world!\n" }, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Content-Length": "157", "Content-Type": "multipart/form-data; boundary=392865f79bf6431f8a53c9d56c62571e", "Host": "httpbin.org", "User-Agent": "python-requests/2.18.1" }, "json": null, "origin": "183.14.133.88", "url": "http://httpbin.org/post" } 6、定制化文件上传: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "post" url = ''.join([host,endpoint]) #自定义文件名,文件类型、请求头 files = { 'file':('test.png',open('test.png','rb'),'image/png') } r = requests.post(url,files=files) print (r.text)heman793 输出比较在,就不帖了。 7、多文件上传: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "post" url = ''.join([host,endpoint]) #多文件上传 files = [ ('file1',('test.txt',open('test.txt', 'rb'))), ('file2', ('test.png', open('test.png', 'rb'))) ] r = requests.post(url,files=files) print (r.text) 输出上,太多内容,不帖了。 8、流式上传: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "post" url = ''.join([host,endpoint]) #流式上传 with open( 'test.txt' ) as f: r = requests.post(url,data = f) print (r.text) 输出: { "args": {}, "data": "hello world!\n", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Connection": "close", "Content-Length": "13", "Host": "httpbin.org", "User-Agent": "python-requests/2.18.1" }, "json": null, "origin": "183.14.133.88", "url": "http://httpbin.org/post" }
环境搭建好后,接下来我们先来了解一下requests的一些简单使用,主要包括: requests常用请求方法使用,包括:get,post requests库中的Session、Cookie的使用 其它高级部分:认证、代理、证书验证、超时配置、错误异常处理等。 本节首先来了解一下requests库中如何发送get请求: 一、看下方法定义: 1、到官方文档去了下requests.get()方法的定义,如下: 2、点击右上角的【source】,看一下它的源码如下: 看到最后一行return,get方法最后是通过调用 requests.request 方法实现的,其实在其它的请求方法如post,put,head,delete等方法都是调用的request方法,然后把请求方法的类型传递给request方法第一个参数。 3、HTTP协议是一个基于请求/响应模式的、无状态的,应用层协议。既然有请求,就有响应,来看下resquest中常用的响应信息: 二、get方法简单使用: 1、不带参数的get: # -*- coding:utf-8 -*- #不带参数的get import requests import json host = "http://httpbin.org/" endpoint = "get" url = ''.join([host,endpoint]) r = requests.get(url) #response = r.json() print type(r.text) print (eval(r.text)) 输出: { 'origin': '183.14.133.88', 'headers': { 'Connection': 'close', 'Host': 'httpbin.org', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.18.1' }, 'args': { }, 'url': 'http: //httpbin.org/get' } 2、 带参数的get: # -*- coding:utf-8 -*- #带参数的get import requests import json host = "http://httpbin.org/" endpoint = "get" url = ''.join([host,endpoint]) params = {"show_env":"1"} r = requests.get(url=url,params=params) print r.url 输出: http://httpbin.org/get?show_env=1 { 'origin': '183.14.133.88', 'headers': { 'X-Request-Id': 'ebe922b4-c463-4fe9-9faf-49748d682fd7', 'Accept-Encoding': 'gzip, deflate', 'X-Forwarded-Port': '80', 'Total-Route-Time': '0', 'Connection': 'close', 'Connect-Time': '0', 'Via': '1.1vegur', 'X-Forwarded-For': '183.14.133.88', 'Accept': '*/*', 'User-Agent': 'python-requests/2.18.1', 'X-Request-Start': '1504755961007', 'Host': 'httpbin.org', 'X-Forwarded-Proto': 'http' }, 'args': { 'show_env': '1' }, 'url': 'http: //httpbin.org/get?show_env=1' } 3、带header的get: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "get" url = ''.join([host,endpoint]) headers = {"User-Agent":"test request headers"} r = requests.get(url) r = requests.get(url,headers=headers) #response = r.json() print (eval(r.text))['headers']['User-Agent'] 输出: test request headers 4、同时带参数和header: # -*- coding:utf-8 -*- import requests import json host = "http://httpbin.org/" endpoint = "get" url = ''.join([host,endpoint]) headers = {"User-Agent":"test request headers"} params = {"show_env":"1"} r = requests.get(url) r = requests.get(url,headers=headers,params=params) #response = r.json() print (eval(r.text))['headers']['User-Agent'] print r.url 输出: test request headers http://httpbin.org/get?show_env=1
接口测试的方式有很多,比如可以用工具(jmeter,postman)之类,也可以自己写代码进行接口测试,工具的使用相对来说都比较简单,重点是要搞清楚项目接口的协议是什么,然后有针对性的进行选择,甚至当工具不太适合项目时需要自己进行开发。 在我们项目的初期,我们采用的是jmeter进行接口测试,当时觉得这个工具上手简单,团队成员学习成本低,并且接口测试的脚本稍微调整一下还可以用来做性能测试。针对这个工具本人也整理了一个系统的文章帮团队的同学入门使用:Jmeter教程索引贴。 不过随着项目规模、团队人数的不断增长,渐渐的这个工具有适应不了当前项目的需求了,为此我们项目也重新开发了相关接口自动化的平台。但是,但是。。。可能是我让大家中毒太深,现在很多同学一提到接口测试关联到jmeter,为此,我深深感到不安。毕竟jmeter只是个工具,换个项目换个协议你是否还能玩转接口测试呢?session和cookie有什么区别?工具又是怎么实现的呢? 为了让大家能更加深入的掌握接口测试,很早就在打算写些简单的使用代码方式来做接口测试的入门教程,因为自己动手写代码有很多问题需要你自己去处理,比如session如何保存,接口依赖如何处理,case如何管理及执行顺序,测试数据如何管理等等题,这个过程也有助于我们更加深刻的理解接口测试和http协议。好了,废话了这么多,下面我们开始吧。 本文主要采用python语言,python中http协议接口相关的库有urllib,urllib2以及reqeusts库,这其中reqeusts库用来起来最方便,因此我也主要采用requests库来做http协议的接口测试。首先来看下需要哪些环境信息: 一、安装python mac下自带安装了python,这个不多说了。 二、安装虚拟环境: 我们在一台机器上可以安装多个python版本,为了使每个版本的环境相互不受干扰,可以安装虚拟环境,安装方法如下: 1、安装virtualenv:pip install virtualenv 2、新建名为venv的虚拟环境:virtualenv venv 3、进入新环境:source venv/bin/activate 4、退出:deactivate 三、安装requests库: >>>pip install requests ps:用python做http协议的接口测试会用到这个库。 四、http测试工具: 一个使用 Python + Flask 编写的 HTTP 请求和响应服务,该服务主要用于测试 HTTP 库。后续测试我们都基于这个网站。 http://httpbin.org/ 五、在本地搭建httpbin: 考虑到测试时要不断访问 httpbin 网站,请求过多担心被拉到黑名单,我们自己在本志搭建一套httpbin服务。 1、安装:pip install gunicorn 2、安装:pip install httpbin 3、启动:gunicorn httpbin:app 至此,环境搭建已经完毕,可以开始玩了~
【问题现象】 在抓https协议请求时,Request和Response显示乱码了: 【解决办法】 第一步:点击 【工具栏-->Proxy-->SSL Proxying Settings...】 第二点:添加需求抓包的请求的域名和端口号: 重新抓包,Request显示正常: PS: 问题解决起来并没有太复杂,不过在网上搜索的资料试过很多都没有起做用,遂在此做个记录。
作为一名测试人员,最大的成就就是像福尔摩斯一样,利用超强的观察力,严密的逻辑推理能力,迅速找出软件的"罪犯",将其绳之以法。可是在成为"福尔摩斯"之前,观察力、逻辑推理能力,是需要不断训练的。这篇文章实际就是软件测试的"犯罪心理学"(初级版):利用软件缺陷数据,对缺陷进行分类汇总,计算缺陷分析指标,进而发现软件生命周期的各个阶段的不足,制定相应改进方法,增强软件过程人为活动的规范性,最终目标提升软件交付质量,提升测试效率 一、缺陷管理库 缺陷管理库记录了缺陷相关的资料,为缺陷分析提供了详细的信息,而只有正确的信息,才能保障正确的分析结果。 1.1 缺陷定义 软件缺陷是指在产品说明、设计、编码阶段中的任何不足。一般要求将需求评审、设计评审、代码检查、测试、项目组内部发现、用户反馈等几种手段发现的缺陷都统一记录在缺陷跟踪系统中,进行统一管理、统计。而目前很多项目缺陷跟踪系统中往往只包含了测试阶段的缺陷统计,在此基础上的缺陷分析势必存在局限性。 1.2 缺陷信息 为了便于缺陷定位、跟踪和修改,需要收集尽量多的有效信息,比较常见的缺陷信息如下: 缺陷描述 被测产品信息:比如App名称、版本号 测试环境:wifi、数据网络、测试环境、生产环境 测试机型:机型、系统版本号 测试步骤 预期及实际结果 复现概率 测试辅助信息:截图、视频、日志 缺陷状态 缺陷优先级:标识处理和修正软件缺陷的先后顺序指标 缺陷严重程度 缺陷发生的组件 缺陷创建时间 缺陷发现人 缺陷责任修改人 缺陷修复时间 缺陷产生原因 在提交缺陷时,需要遵循以下5个原则: 准确性:缺陷每个组成部分描述准确,不会产生误解 完整性:复现该缺陷完整的步骤、截图、日志 一致性:按照一致的格式书写全部缺陷信息 简洁性:只包含必不可少的信息,不包括任何多余的内容 清晰性:每个组成部分的描述清晰,易于理解 这一步其实可以理解成培养测试人员的观察能力,信息收集能力。只有不断观察、收集正确信息,才可以为后续的侦查做好准备工作。 二、缺陷分析 缺陷分析是在形成缺陷管理库的基础上,对缺陷进行宏观及微观纬度的分析。通过缺陷分析,发现各种类型缺陷发生的概率,确定缺陷集中的区域,明确缺陷的发展趋势,追踪和分析缺陷产生的原因。在此分析基础上,对软件生命周期中各个角色、项目流程做改善和优化,提高软件测试质量,提升测试效率。 缺陷分析仅仅是一种手段,而非最终目的。利用缺陷分析结论,反思和回溯缺陷产生的各个阶段,思考如何避免类似问题,不再踩坑,在下次测试中得到提升,才是我们想要的结果。同样的,缺陷分析的成果是一个持续改进优化闭环的过程,它是测试人员潜移默化中测试能力的提升,也是项目流程中各个角色共同保障产品质量意识的推动。例如缺陷分析发现很多需求缺陷是到测试阶段才发现,那么就有必要加大需求评审力度;缺陷分析发现开发修复缺陷引入新缺陷比例很高,那么开发团队在修复缺陷的时候要考虑到对周边区域的影响,并且要通知相关区域的专家加强代码审查。当然测试团队也要尽可能多的在相关区域做一些回归测试。大家可以结合自身项目来利用缺陷分析优化项目实践。 三、宏观缺陷分析技术 宏观缺陷分析是指对缺陷信息进行分类和汇总,利用统计的方法计算分析相关指标,编写缺陷分析报告的活动。宏观缺陷分析的方法很多,这里主要关注缺陷发展趋势分析、缺陷分布状况分析、缺陷注入-发现分析。 3.1 缺陷发展趋势分析 项目管理中一项非常重要但十分困难的工作就是平衡进度、质量和成本。测试人员可以提供缺陷提交、缺陷修复的趋势图表,帮助管理者从中发现一些简单的缺陷发展趋势(这种缺陷可以是本文论述的广义缺陷发现手段确定的,也可以是单纯的测试手段发现的),从而了解软件质量趋势。这里给出一个常用的分析图,x轴代表时间,y轴代表以下四种类型缺陷的数量: 发现数:累计的所有被发现bug的数量 关闭数:累计的所有被关闭bug的数量 日(期)发现数:当日(期)发现的缺陷数量 日(期)关闭数:当日(期)关闭的缺陷数量 图1:缺陷分析发展趋势图 3.2 缺陷分布状况分析 3.2.1 缺陷严重程度分布 缺陷严重程度度量有助于识别不同严重程度缺陷在所有缺陷中的比重,有助于开发测试人员资源的计划和分配。这里给出一个常用的缺陷严重程度分析图,x轴代表时间,y轴代表各严重级别的缺陷数量。 图2:缺陷严重程度分布图 通过缺陷严重程度图表,分析各严重程度缺陷发现趋势,判断产品质量是否趋于稳定。如果高严重程度的缺陷大量增加通常意味着产品质量出现问题。 3.2.2 缺陷模块分布 按照缺陷对应的产品组成部分来汇总缺陷数据,利用这样的分布,可以找出我们产品高危模块,针对高危模块,调整测试策略。 3.2.3 ODC(正交缺陷分析) 正交缺陷分类法(Orthogonal Defect Classification,ODC)介绍了一种不同于大家常用的非常有效的软件缺陷分类及分析方法,它定义了八个正交的缺陷属性用于对缺陷的分类。所谓正交性是指缺陷属性之间不存在关联性,各自独立,没有重叠的冗余信息。 对于缺陷提交者,他需要给这个缺陷分配“活动(Activity)”、“触发(Trigger)”、“影响(Impact)”这三个属性。 Activity:项目生命周期的一个阶段,该缺陷发生在该阶段,例如需求、设计、代码阶段,即缺陷发现阶段 Trigger:可以理解成测试的手段 Impact:对用户的影响,例如安全性、易用性 当一个开发人员关闭一个缺陷时,他可以分配“阶段(Age)”、“来源(Source)”、“限定符(Qualifier)”、“类型(Type)”以及“目标(Target)”这五个属性。 Age:描述缺陷对应的代码属于新代码,旧代码,还是修复bug引入 Source:定义缺陷来源,是自身代码问题,还是第三方代码导致 Qualifier:指明了所进行的修复应归于缺失,错误或者还是外来的代码或者信息 Type:缺陷真正的原因,例如初始化、算法等 Target:描述缺陷是由于设计还是编码引入,即缺陷注入阶段 关于ODC分析方法,需要结合实际项目,对不同属性进行筛选,优化不同属性对应的值。软件缺陷分析方法:ODC 这篇文章中详细解释了ODC各属性及对应的值。 3.3 缺陷注入-发现矩阵 利用缺陷的两个重要属性:缺陷发现阶段、缺陷注入阶段,分析缺陷数据,绘制出"缺陷注入-发现矩阵",从中分析项目生命周期各个环节的质量,优化相关流程。 缺陷移除率:(本阶段发现的缺陷数/本阶段注入的缺陷数)*100%,它反映的是该活动阶段的缺陷清除能力 缺陷泄漏率:(下游发现的本阶段的缺陷数/本阶段注入的缺陷总数)*100%,它反映的是本阶段质量控制措施落实的成效 图3:缺陷注入-发现矩阵 如上图例子,需求阶段一共注入了34个缺陷,需求评审时只发现了4个,设计过程中发现了15个,编码和单元测试阶段发现了12个,系统测试阶段发现3个。这样,需求阶段的缺陷移除率 4/34*100%=11.76%。这个结果说明,我们需要重新审视需求评审,加大需求评审力度。另外,编码阶段的缺陷大部分依赖于系统测试发现,很显然,项目开发过程中的单元测试和集成测试活动开展不够深入。我们可以进一步分析这些系统测试出来的测试缺陷,是不是可以被更前端的评审/测试/设计讨论活动所替代。 四、微观缺陷分析技术 微观缺陷分析是指从单个有价值的缺陷入手,追踪和分析缺陷产生的本质原因。并不是所有的缺陷都有必要去做微观缺陷分析,因此首先需要挑选"合适的缺陷"。这里给出几点建议 选择典型有代表性的:同类型的一系列问题 选择有发现难度:积累缺陷库,对测试用例做补充 选择有推广意义的:该缺陷很普遍,可以推广到其他业务线 再挑选合适的缺陷后,我们紧接着需要收集该缺陷相关的有效信息进行下一步缺陷原因分析。这些缺陷信息包括提交缺陷时信息,同时也包括和开发讨论获取的信息。 接着就是追踪缺陷产生的真正原因。网络上有很多总结的分析方法,有"望、闻、问、切"诊断法,有"5W"法,还有"探案分析法"。其实个人觉得在这一步骤中,更多需要积累经验,善于追根究底,多问为什么,多理解产品实现逻辑,产品设计思路,有了这些基础之后,合理的推理分析即可。下面这两篇文章是非常好的结合实践总结的微观缺陷分析,大家可以通过他们的分析积累经验。 不会做bug分析?套路走起~ 缺陷分析的正逆向 原文作者:桃子妈咪原文链接:http://www.jianshu.com/p/1bb7ff2d7c6f
一、什么是辅导? 传授:有前期知识或经验的人能把这种智慧传授给他人,以实现产能最大化的目标。 帮助员工发现自我:帮助他人释放未开发的潜能,帮忙他人坚持自我并实现对自我的期望。 二、 哪些行行为有助于/阻碍辅导? 有助:倾听、提问、避免臆测、引导式发现、参与、共同工作、关注过程、追求效果、承担责任、放下架子 阻碍:讲太多、不提问直接指示、臆测、只给答案不给方法、过度控制不授权、命令、只谈工作、只看表象、指责、摆架子 三、辅导风格 低产能员工:给予较多指示 中间:促进员工自我发现 高产能员工:给予较少指示,适当授权 PS: 没有一种风格适用于所有情况。 根据情况和辅导对象选择恰当的风格。 适当的时候从一种辅导风格向另一种风格转换。 四、辅导技巧: 问问题 积极倾听 分享经验 列出结果 选择性沉默:鼓励开诚布公 口头和非口头的信息传达:总结辅导对象传达给你的信息能力 五、辅导流程-GROW GROW模型阐述了辅导流程:明目标(去哪儿)——谈现状(现在哪)——找方案(怎么去)——做计划(行动计划),在管理者有效完成辅导的同时也帮助员工成长。 六、辅导工具: 辅导循环:解释->示范->实践->反馈 适用于具体的工作且领导有充分的时间辅导下属 反馈技巧:做的好的要继续做更多,做的不好的要减少次数。 三人教学:1教2,2教3 适用于快速铺开、复制 挑战:中间传递者(2)的学习效果 解决办法:2在教3之前先给1讲,如果ok再讲。 学教用:先进行个人学习,然后与他人分享,最后运用所学解决问题 适用于领导工作非常忙,时间有限,无法花大量时间进行辅导。 七、总结: 如果你是领导者,你就是一名教练和老师。 辅导是要创造未来,不是填补空白。 辅导包括个人和团队。 辅导整合绩效和发展,引导他人走向更高的层次。
工作成熟度 工作成熟度 一个人的工作成熟度会随着工作环境的改变而改变,一旦下发的工作成熟度有波动,你对他的”最佳管理风格”也必须随之变动。 一个经理人最主要的职责,便是激发下属的最佳表现。每个时代流行的管理风格其实和当时的激励的理论有关,研究学者必须下没有所谓最佳管理风格的定论。 在大公司,中层经理人的工作经常轮调,以增加对他们的锻炼。虽然轮调部门的背景及工作内容通常极为类似,但最后的产出经常有较大差异。不论是经理人还是部门都无法一直维持其高产出或是低产出,而总是会有高低潮。显而易见,高产出是某些经理人及某些部门特定组合带来的结果,这也证明没有任何一种管理风格能放诸四海而皆准。 环境不同,表现不同 虽然环境不同,表现不同,也没有最佳的管理风格。但有一种变量能告诉我们在不同状况下的最佳管理风格,这个变量称之为“工作成熟度”。 工作成熟度:涵盖了下属是否为成就导向、是否能承担责任、他们的教育背景、受过什么训练与以往的工作经验等。 一个人或一个部门可能在某件事上有很高的工作成熟度,但在另一件事上则犹如初出茅庐。一个人在某种程度的复杂性及不确定性下,可能有很高的工作成熟度,但一旦这个工作的复杂性增加或是工作内容突然改变,他的工作成熟度就会下降。 随成熟度改变管理风格 因此,随着工作成熟度的改变,管理风格也必须随之改变。 当工作成熟度低时,最有效的管理方法是提供明确且详细的指示,在这种情况,上司要告诉下属该做什么事、何时完成、如何着手。这时的管理要采用非常有组织的领导作风。 随着下属的工作成熟度渐增,最有效的领导方式也由组织化转为沟通、情绪上的支持与鼓励。相较于下属手上的工作,经理人应花更多的心思在这个下属身上。 而随着工作成熟度的越来越高,管理风格也会一再改变。在更成熟的阶段,经理人对下属的干涉也应该进一步降低,主要管理目标应聚集在确定下属的努力方向是否合乎部门的需求上。 同时,不管工作成熟度落在哪一个阶段,经理人都应当随时且适度地监视下属的工作,以避免任何突发状况。 下属的工作成熟度及对应的有效领导风格 下属工作成熟度 有效的领导风格 低 组织化、任务导向,告诉员工该做什么,何时完成及如何着手。 中 注重个体,强调双向沟通,给予情绪上的支持及鼓励。上司与下属之间相互了解。 高 经理人的参与程度降低,彼此建立起工作目标及监督系统。 下属的工作成熟度是决定有效管理风格的基本变量。在思考管理风格以及真正执行时,不要让“扮白脸”或“扮红脸”成为影响决策的因素。千万记得:我们真正在意的是效率。 生命成熟度 这套理论事实上和孩子关系的发展极为相仿。随着孩子的长大,父母的管教风格也会因孩子的“生命成熟度”或孩子的年龄面改变。当孩子还小时,父母必须告诉他什么碰得、什么碰不得。当他渐渐长大,开始凭他的直觉做事时,父母会鼓励他独立行事。随着孩子越来越成熟,可能会离井背乡到外地求学,此时父母只是在一旁注视孩子的生活,一旦孩子所处的环境产生巨变,他的生命成熟度又不足以应付时,父母的管教风格可能就要加到之前的阶段。 建立共同的价值观 如果希望希望管理风格能够从有组织化向旁观监督转化,那么先建立起共同的行事准则及决定优先级等,绝对能让企业一体运作的价值观势在必行。 管理风格与管理杠杆 身为经理人,必须赶快提高下属的工作成熟度。管理具有高度工作成熟度的员工比采用高度组织化的管理风格能省很多时间和精力,同时,如果员工了解组织的价值观且具有较高的工作成熟度时,主管便可以开始分权,进而提高自身的管理杠杆率。 管理风格并没有优劣之分,但重要的是应基于员工作工作成熟度而决定采用哪一种管理风格以提高效率。 管理者是否应与员工建立友谊 这件事有利有弊,友谊可以促使管理者与员工进展到有效的双向沟通阶段。但不应该把友谊相关的社交活动与工作混为一谈,社交活动并不能直接在工作上产生帮助。 假设你必须对你朋友的绩效作很严苛的评估,这时如果你开始觉得胃不舒服甚至想吐,说明你最好不要在办公室交朋友。反之,如果你依旧呼吸顺畅,那么你建立的友谊有可能增进你和下属的工作。
管理杠杆率 经理人产出的定义 经理人的每一项管理活动对整个组织都有或多或少的影响。至于对整体产出的有多大,则在于这些活动的杠杆率大小。 经理人的产出 = 他直接管辖部门的产出 + 他间接影响所及部门的产出 经理人从事的活动有很多会影响别人,不管是他提供意见与判断、指示方向、告诉下属资源分配方式,还是侦测错误等等,对于产出他都是不可或缺的关键,但这些活动和产出在本质上仍是两码事。“活动”是我们日常真正在做的事,看起来有些烦琐;而“产出”则是我们的成就,与活动相比就显得重要的多。 经理人必有有同时处理数件事的能耐,此外,还得知道何时该转移注意力,把精力放在当时最能促进组织产出的活动上,即:他必须了解哪些活动有最高杠杆率。 管理活动分类:收集信息、传递信息、制定决策、给予提示和为人表率。 信息收集 经理人要增加并维持自身吸收和过滤信息的能力,信息收集途径:看邮件、看报告、开会、和同事交谈、看用户反馈、看产品数据、试用公司产品: 书面报告:时效性较差,但可建立数据文件、过滤并信息,避免遗漏,备份留档以备查阅,比口头报告更准确,更规范,更严谨。 口头交谈:时效性较好,通常价值性更高。但通常只能提供概括的、不完整的且有时不甚正确的信息。 你绝对不能只靠某一种特定的信息来源,你的信息来源彼此应该有互补,虽有重复但可以前后对照信息的正确性。 经理人不但收集信息,同时也是信息的来源。他将信息传递给下属以及影响力所及的部门,包括既成事实,目标,优先事项以及做事的方式,这正是“授权”能否成功的关键环节。所有其它的管理活动,如传递信息、制定决策或是做你下属的学习对象,都是以你所拥有的信息为基础。 决策 你对一件事情了解的程度将会影响你的决策,这便是为什么收集信息对一个经理人如此重要。决策可分为两种: “未雨绸缪型“:如将公司资源依据未来将要进行的事情作适当分配。 “亡羊补牢型”:应对可能正在产生或已经产生的某种问题 给予提示 这种动作不只在传递信息,还同时在设法将事情或是人引导到你觉得对的方向上。这也是往往会让我们花大把时间的重要管理活动。与制定决策不同的在于,决策经常会有明确的方向与结果,提示则不然。 为人表率 我们如何行事,常常会成为下属、同事,甚至你的上司的模范。经理人应该知道怎么用他自己的那一套做法发挥他的影响力,而且要让别人看得到。 经理人的工作大部分是在分配资源,但其中最重要且每天例行的工作便是调配自己的时间,如何运用时间是一个人是否能成为领导者或模范的最重要的一点。 管理杠杆率 杠杆率:各单项管理活动所带来的产出 经理人的产出 = 组织产出的总和 = 杠杆率A * 管理活动A + 杠杆率B * 管理活动B……….. 为了提高产出,经理人应该把精力放在杠杆率较高的活动上。经理人的生产力即其每个单位时间的产出,可通过以下3种方法增加: 加快每一项活动进行的速度。 提高每一项活动的杠杆率 调整管理活动的组合,摒除低杠杆率的活动,代之以高杠杆率的活动。 高杠杆率的活动有: 当一个经理人可以同时影响很多人时。 当一个经理人要个简单的动作或一段简短的话,可以对别人产生长远的影响时。 当一个经理人所提供的技术、知识或信息,会对一群人的工作造成影响时。 如传授知识、技能或其价值观给下属,关注用户的反馈,绩效评估,授权,专家影响力,都属于高杠杆率活动。 杠杆率有多大,则在于“何时”从事这项活动。事先便计划好要比后来才亡羊补牢地向其它人解释、要求有更高的杠杆率。为了提高管理活动的杠杆率,一定得把“时效”的重要性铭记于心。 杠杆率也有可能是“负”的---有一些管理活动只会减少组织的产出,如: 会议的关键人物没有准备就到达会场 经理人情绪低下,影响员工士气 经理人越权干涉别人的工作,影响别人积极主动性 经理人做出错误决策,浪费人力物力 拖延决策 杠杆率有多大,则在于“何时”从事这项活动。事先便计划好要比后来才亡羊补牢地向其它人解释、要求有更高的杠杆率。为了提高管理活动的杠杆率,一定得把“时效”的重要性铭记于心。 管理的艺术便在于如何在那么多看来很重要的活动中,选出一两项最重要的,然后全心全意的去做。 授权也有杠杆率 经理人的时间随着其层级不同而有不同价值,授权遂成为管理中重要的一环。“授权人”和“被授权人”的关系间有一个必要条件:这两者必须有相同的信息基础,以及在开展工作和解决问题上有一套彼此认同的方法。 如果你的被授权人猜不透是滞自己已被授权或不明白被授权的范围,将会有极高的负杠杆率。 没有完备监督计划的授权等于渎职,你绝对不能抽身,即使你已经授权,你还得负成败责任。监督不是干涉,而是通过不时的检查,来确定活动的进行是否正常。 (授权)监督原则 在产品价值最低时就进行监督:越早检查成本越小,在软件开发测试中,QA越早介入越好就是这个道理。 设定检查频率:采用不定期抽查,深入了解“细节”,并且对不同的下属进行不同的的采样方法。至于抽查频率,应以员工对授权项目的熟悉度(工作成熟度)而定,新人需要增加检查频率,下属渐入佳境后,便可以降低监督频率。 工作成熟度:是指其对特定项目的经验或熟悉度,而非对一般事情而言。 授权下属做某些特定决定的监督原则:监督制定决策的过程。可以要求下属在制定决策前先将细节讲清楚,接着,我们通过问他一些重要的问题来检测他是否真的仔细考虑过,如果他的回答很有说服力,便可通过。这样一来,监督的人不用一一深入细节便能确保决策的品质。 提高管理活动的速度 增加经理人产出的最明显的方法,便是提高其工作的速度,其中关系如下: 常被用来提升经理生产力的方法时时间管理,常用办法: 找出限制步骤:重要的、紧急的事情优先安排。这样的情况下有空余,再安排别的活动。 类似工作集中在一起做:减少“准备时间”以及“思考活动”的时间。如定期处理邮件,而不是时时处理。 安排好你的日程表:敢于Say NO!对日程表应用“弹性空间”不要排的太紧凑。 建立指标: 尽量评估在每项活动上所花的时间,虽然可能不准且很难但总归有好处,且有经验之后会更准。应该应用这方面练就的直觉来规则你的工作。 存货法:留一些重要不紧急的活动,在自己不太忙时可以做,另一个好处是避免经理人一有空就去干涉下属的工作。比如体验产品,学习技能等。 标准化:设法让处理相同事情的方法更趋一致,标准化后就不用每次想应该怎么做了,按步就班地开展即可,但同时不要扼杀的思考的空间。 干扰与突发状况解决办法 标准产品:经理人的“顾客”—他的下属或其他部门的人,不会一天到晚总有新问题。如果经理人能高潮将常见的问题归类并准备好答案,便能减少处理问题的时间。当然,也可将其授权给其他下属来处理。化不规律为规律。 或者运用“类似的事情集中一起做”的原则,很多问题可以留到部门会议或“一对一”会议再一起处理。
领导力的5个层次-领袖特质 ---领导力的最高成就在于努力促使其它领导者迈向第四层次个人发展 一、 前言 很少有人能最终达到第五层次,因为这一层次不仅是基于其它四个层次,同时需要高水平的技能和天分。第五层次的领导者需要做的是把其他领导者提升到第四层次,这需要付出很多努力。 二、 领袖特质的积极方面(你的影响已经超越你所及与所处的时代) 1、具备领袖物质的领导者创造出顶级的组织 第五层次的领导者致力于培养其他领导者成长为第四层次的领导者—那些能够造其他领导者的人。 第五层次的领导者授权给很多人去领导,这就提高了组织中每个人的上限,组织中每个的都获得大量的机会,随着每个领导者的成长,整个组织不断地发展壮大。 2、第五层级领导力在组织内部会留下宝贵的遗产 对于一位领导者最终的检验是他留给其他人坚持下去的信念与力量。 3、第五层次领导力为领导提供了延伸的平台 人们尊敬第五层次的领导者是因为他们是谁以及他们报代表的东西,这赋予他们一个更为广阔的平台与延伸的影响力。 三、领袖特质的消极方面(唯我独尊的自大情绪或许在你的心中悄然蔓延) 1、身居巅峰会让你认为自我实现止步不前 在最高层次的顶峰领导者一大危险与最低层次的职位型领导地者相似:认为他们已经自我实现而止步不前。这一点听起来还有些讽刺意味。 通过学习,你最终会超越局限,继续前行。 2、身居巅峰会让你坚信自己的力量自认为天赋异禀 如果你成为第五层次的领导者,不要忘记,你和其他人一样,都是从最底层职位型领导者开始的,你必须努力去构建人际关系,证明你的生产力,投资于别人的人生。如果你成功了,那也只是因为这一路上,有太多的人与你同行。 3、身居巅峰会让你失去焦点 无论你在领导力征程中处于何处,永远不要忘记你奋斗到现在的位置所努力取得的不会帮你成长到下一层次,每前进一步都需要全神贯注,都需要有强烈的意愿去不断学习、适应、制订战略、奋力工作。没有焦点、谦逊与辛勤工作,你是不会达到最顶峰的。 四、 最佳行为选择(如何做出更多超越自我的贡献) 1、确保在最高层次给他人留出足够的发展空间 终极领导者能够培养他人,直至后进者最终在知识与能力上都超过自己。 终极领导者的焦点是致力于提升他人的优势 2、持续不断地指导潜在的第五层次领导者 3、打造领导者核心圈让自已脚踏实地 4、为组织做好那些只有第五层次领导者可以完成的事情 5、为你的后续接班做好规划 6、留下一份下面的遗产 五、帮助别人迈向领导力的巅峰 1、确定并创造一些他们必须学习的”熔炉型”领导力课程 2、寻找那些他们可以从中学习的出乎意料的“熔炉时刻” 3、将你自身的“熔炉时刻”作为教授他人的行动指南 4、将后进领导者“暴露”于那些能够影响他们的人与组织面前 六、成长指南 保持谦逊与可教的姿态 保持你的核心焦点 建立起合适的核心圈让自己时刻保持脚踏实地 做好那些只有你可以做的事情 创造一个超动力的领导力发展环境 在最高层次留出发展的空间 培养你的顶尖领导者 规划好你的传承大业 计划好你能留下的“遗产” 将你自身在领导力方面的成功作为实现更伟大事业和平台
领导力的5个层次-个人发展 ---立人者方能立已 一、 前言 第三层次领导力的重点在于个体与团队的生产力。要想获得能够领导精英的较高领导力,领导者必须实现从生产者到培养者的转变。 第四层次上的优秀领导者投资时间、精力、金钱和思想,来培养其它领导者。他人观察每一个人的头衔、地位、年龄和阅历,试图度量其发展为领导者的潜力。鉴别并发发展潜在对象对组织有着积极的影响,因为发挥人的最佳状态能够促进整个团队保持最佳状态。 第四层次的领导应把关注点从组织中其他人的生产力转移到他们的潜力开发上去,这一举措将给组织带来革命性的变革,并带来更光明的未来。 二、 个人发展的积极方面(组织的潜能得以提高) 1、 个人发展使你在众多领导中与众不同 大多数领导者都在寻求各种途径来发展自己的组织,但他们通常致力于提高生产力,这是不对的。如果想要组织得到更好的提升,人们需要促进组织中每个成员的发展,特别是促进企业中领导的个人发展。 2、 个人发展确保可持续发发展 真正体现你领导能力的不是你在场时大家的表现,而是你不在场时大家的表现。 如果没有授权和完全的自主,人们和组织不会有太大进步,因为他们受上司的能力所限,反映出民司的优缺点,不要让自己成为组织发展的阻碍。 有效率的组织应该像雁群一样,呈V安状飞行,分担各自的负荷。 领导者将工作的所有权转交给工作的执行者 领导者创造所有人都认真负责的工作环境 领导者对员工的个人能力发展提供指导 领导者有很快的自学速度,并鼓励他人快速学习 3、 个人发展促进其它人履行其领导责任 个人发展本质上是共同承担完成某项任务的责任,因为很多事情光靠教与学是不够的,需要不断实践。如果你授予别人责任与权力,他们会去学习并开始履行领导责任。 领导者关注人的发展,赋予别人领导权力,有益于被领导的人,一旦他发展出新的领导者,他们会做的更好并且帮助其它人更好的工作。如此一来组织的效率也会提高。同时新的领导者能够分担一部分工作和负荷。 如果你的行动能够激发别人去追求更高的理想、学习更多的知识、做更多的事情、成国更伟大的人,那你你就是一个优秀的领导者。 4、 个人发展促进领导者成功 很多领导者不想与其他人分担责任,因为他们不想因此失去自己的权力。 如果你与其他人共享领导权,你会获得更多的自由与时间,这样不仅扩大了他们的行动空间,也扩大了你的领导范围。而且你有时间去做更为重要的事情,如思考、规划蓝图和制订战略。 把任务转交给其他人是很难的,有个经验是:如果团队内有任何人的工作质量能有我工作的80%或以上那么好,我就可以放手让他来做这件事。高效的领导者,必须实现从完美主义到实用主义的转变。 5、 带来更大的个人成就 生命的目的不是成功,而是成长与分享。当你回首往事时,你会发现你给别人带去的快乐比战胜他们更能让自己得到满足。 三、个人发展的消极方面(促进人员发展需要深刻的成熟度和高水平的技能) 1、自我为中心会使领导者忽视其他人的发展 成熟是一种能够跳出自我的圈子思考的能力,能够站在别人的视角观察事物。 一旦成为领导者,你就失去了为自己考虑的权力。第四层次的领导者需要把80%的时间放到帮助其他人进行个人发展的方面。 2、缺乏安全感会使领导者认为员工的成长是对其的威胁 再优秀的个人能力也不能弥补缺乏安全感所带来的缺失。 3、 短视行为会使领导者看不到个人发展的需求 把任务交给其他人做而不是自己亲自做,虽然自己完成任务总是比训练他人更快捷,但我们必须转变思维,成为人才的开发者。 4、 奉献精神的缺失会使领导者不愿去从事个人发展的艰难工作 随着领导层次的不断提升,需要面对的困难越来越多,职位型领导者不需要太多技巧就可以领导他人,认同型领导者依靠人际关系来领导他人,生产型领导者靠成果领导他人。第四层次的领导者需要培养他人成为领导者。 任何人只要能够同他人关系融洽,可以亲自生产,传递信念与愿景,他就可以吸引到追随者。但吸引、培养并领导其他领导者是更加困难的。 四、最佳行为选择(如何促进个人发展) 只有领导者才能将其他人培养成领导者。 不亲身实践,没有人能够真正理解领导力。领导者需要去发现(招募与定位),展示(示范与装备)和培养(培育、授权、衡量)后起之秀。 1、招募—-尽可能发现最优秀的人 成功招募的关键在于你对目标人才有清晰的定位,当你知道你要找什么的时候,想要找到它就容易很多了。如下是寻找潜在领导者时候,运用的4C框架: 化学效应(Chemistry): 如果你很认真的考虑招募或者提拔某人,让你的团队与他接触一段时间,看一看你的团队是否喜欢他。如果不喜欢的话这个人或许不是那么的合适。因为人们更愿意同自己喜欢的人一起工作。 品质(Character): 良好的品质容易建立信任,信任让人际关系牢固,牢固的人际关系使得导师般的指导成为可能。对于那些品质不信任的人是难以培养的。因为优秀的领导者是被发现,而不是被改造的。 能力(Capacity): 第四层次的成就是将每个人的能力发挥极致,而挫折将原本不具备的素质挖掘出来。考察潜在领导者的能力可以从以下几个方面入手: 压力:承受并克服压力、失败、最后期限以及挫折的能力 技能:完成特定任务的能力 思维:善于创新、提升战略、解决问题以及适应环境的能力 领导力:他们凝聚人心,构建团队的能力 态度:他们在逆境中乐观享受、坚忍不拔的能力 贡献 (Contribution): 一些人是具备未知力量的,他们对于团队的贡献超出他们的职责所在,他们提升每个团队成员的表现。 2、定位—-将合适的人放在合适的位置 只招收优秀的人是不够的,领导者必须对每个人的长处和不足都有清晰的认识,明白他们如何才能满足团队所需,清楚他们在团队最适合的位置,并让他们各司职。 3、示范—-展示给他人如何领导 在培养他人时,以下几点必须要诚实地做赤示范表率: 真实性:培养他人的基石所在 服务心:培养他人的灵魂所在 成长:培养他人的衡量尺度 卓越:培养他人的标准所在 激情:培养他人的动力所在 成功:培养他人的目的所在 4、装备—-帮助他人更好的工作 仅仅只是告诉团队成员他们需要做什么是不够的,这也不是培养他们。与之相反,领导者必须帮助他们做工作并且要做好。 领导者如何装备自己的员工?办法是“五步装备法”: 第一步---我做(能力) 第二步---我做,你跟我一起做(示范) 第三步---你做,我跟你一起做(辅导) 第四步---你做(授权) 第五步---你做,别人跟你一起做(复制) 这种方法不仅可以装备领导者,也可以教会他如何去装备别人。 5、培育—-教他们学会生活 个人领导的意义在于挖掘那些被 领导的人的潜质,将其培养成为真正的人(包括工作和生活),从而兴旺发达。促进他人领导力成长的三大核心要素为:评估、挑战与支持。 评估:作为第四层次的领导者,你应该持续不断地从低下在领导与培养的人身上寻找生活技能的缺失处。 挑战:如果你已经建立起牢固的人际关系并且通过示范与生产力在第三层证明了你自己,此时是让他们接纳你的领导力并接受来自你的挑战的好时机,可以让员工做如下的事: 读一些优势领域的书 参加那些可以鼓舞自己的会议 在他人的最佳位置承担一些新的、有挑战的任务 实践一些能够慢慢培养品质的自律行为 同你定期见面寻求指导 核心思想是在你能看到的他们需要提高 的每个领域去挑战他们,前提是确保你获得他们的认可。 支持:没有人能够脱离他人的帮助与支持而走在人生的前列,为了帮助员工我会让他们在需要的任何时候与我见面。他们通过问一些具体问题来控制会面的进程,我会尽可能回答他们的问题,同时,下次我们会面时我会询问他们是如何运用所学的东西。 6、授权—-授权让他人取胜 最佳的管理者具备足够理智来挑选优秀的人完成他们想做的事,也具备足够的自制力避免在他们做事的时候搅扰他们。 7、衡量—-评估那些你培养的人以将其努力最大化 通过判断你团队成员在多大程度上能够独立工作,可以衡量他们在领导力培养中所处的位置。从“最不独立”到“最独立”,分为以下六个维度: 1、调查事件:报告,我来决定要做什么 2、调查事件:从正反两个方面报告可选方案以及你的建议 3、调查事件:让我知道你要做什么,但要在我同意后才去做 4、调查事件:让我知道你想做什么,我不反对就骈做 5、采取行动:让我知道你已经做了什么。 6、采取行动:没有进一步沟通的必要 当你在培养团队成员时,可以基于他们的典型表现,根据这六个维度来衡量他们在领导力培养中所处的位置。 五、 迈向第五层次的信条 1、领导力的最高目标是培养领导者,而不是争取追随者 提升领导者个体的人生是领导力培养的最高目标,当你帮助他人在为领导者时,你改变了他们的人生、看待世界的方式、他们的能力以及他们同别人交往的方式。同时,你提升的不仅仅是他们,还有每一个他们接触到的人,这也是你如何改变世界最好的途径。 2、为了培养领导者必须营造一种领导力文化 3、培养领导者是一份人生的奉献而不是工作的承诺 六、成长指南 1、愿意时刻保持自身的学习成长 保持一种“可教”的状态,就是每个人、每件事都可以都给我一些东西 时刻拥有一份成长计划,你果你不曾有意识的自我成长,想要帮助他人有意义的成长是不可能的。 2、决定那些值得你去付出努力的人 3、战胜你的不安全感 4、尽你的所能招募最优秀的人来培养 5、承诺付出必要的时间来培养领导者 首先为“解放”你自己建立一个支持系统,当你事必躬亲时,你很少有时间去指导他人。 其次,基于他的潜质决定你在每个人身上投入的时间,领导者的价值在于他在他人身的上投资,而不是他能够亲自做什么。 6、创建一个个人发展过程 观察、辨别与分析的能力对于培养他人必不可少。 第四层次的领导者能够辨别他们身上的能力,随机应变地与他们共事,有所差别地因材施教,而 不是一视同仁地领导。 7、绝不在工作中“单打独斗” 在第四层次上培养领导者的秘诀之一是让你所指导的人尽可能的待在你身边,这样你才能了解他们在不同的情况下怎么想,怎么做的。当你在示范领导力时,他们能够认真观察。当他们准备好时,你可赋予他们一些你可以监督与掌控的职责时,授权让他们放手去做。 8、协调好发展的“软”、“硬”两面 9、担负起激励他人的重任 10、作为领导者,行为榜样与教练保持平易近人
领导力的5个层次-生产 ---能否化梦想为现实是区别真正领导者与自封领导的试金石 一、 前言 生产力能够鉴别并区分哪些领导者能够对组织产生重大深远的影响 而哪些毫无建树,不仅他们个人本身高产,更能帮忙团队生产。这种能力赋予第三层次领导者以自信心、公信以及增长的影响力,生产层次是领导力真正起飞的地方。 二、 生产的积极方面(由此确立了领导力上的公信力) 1、 领导力的生产层次赋予领导者以公信力 最终成果的生产能力从来老师区分成功与否的分界线,也是领导力资格的认定线。 第三层次的领导者应亲自将自己的员工带到人们想去的地方,而不是将他们发送出去,因为人们总是相信我们所做的而不是我们所说的,这就是榜样的力量。 如果我们做工作追求卓越,帮忙他人高效生产,我们就会获得巨大的领导公信力。 2、 为他人塑造并制订了可观可感的评价标准 高效生产的领导者是其所领导员工的表率,他们自身的生产能力为整个团队建立 了标准。 那些能够生产价值的人都有机会在一个更高层次上影响他人,如果你可以建立起牢固的人际关系并能够生产价值,那你就能成力一名高效的领导者。 3、 让未来梦想与愿景更清晰实际 生产层次的领导者通过实际行动来传递理念,帮忙员工以一种前所未有的方式来理解它,当追随者看到积极的成果,看到眼下目标得以实现,他们会对未来梦想的实现有更清楚的认识。 4、 能解决大量的实际问题 生产层次的领导者必须在克服困难,扑灭险情,纠正错误,指导他人等方面积极有所建树。不能总是把解决问题的重任托付给其它人。 5、 创造巨大的前进动势 当一个领导有方的团队能保持高昂的士气与高效的生产力时,他们就会获得前进的动势,犹如在河中游泳,顺着潮水游时,前进的幅度是巨大的且与自身的速度与力量无关。顺势而为,你将会前进的更快。 6、 团队的构建基石 胜利者吸引他人,构建一个胜利团队的关键是甄别并留住那些你所吸引到的最优秀的人。 三、 生产的消极方面 1、 富于生产力会让你在自己不是领导者时把自己当成是 所有伟大的领导者都是富于生产力的,但一个生产者并不一定是领导者。个人的成功并不总会转变为团队的成就。真正的领导力能让整个团队更富有生产力。 优秀的领导者在第一层次赢得自己的领导职位,在第二层次获得员工认同,在第三层次商效生产,并愿意将整个团队提升到更高的层次。 2、 对于结果有沉重的责任感 不论多么伟大的领导者都不久维持,除非他不断取得新的胜利。 高效的领导者明白领导力的代价就是将整个团队成败的责任扛在自己肩上。 3、 生产型领导者需要做出艰难的抉择 与那些怕做的错误决定想比,我更加追悔那些我没去做的决定。 做对的事很好,都会他人做对的事更好---其实也更容易 4、 领导力生产层次要求持久关注第二层次 在有所成就的同时,继续建立良好的人际关系,否则最终你会发现自己又退回到了第一层次。 四、 最佳行为选择(如何利用好领导力的生产层次) 1、了解你的个人禀赋如何能为组织的愿景有所贡献 做好你自己所擅长的事,那些看到你做事的人会再次来看你做事,并告诉其他人应该再来看你做事。 2、为所需要完成的任务规划好愿望 帮忙员工为“成功”定义 帮助员工致力于成功的实现 帮忙员工经历成功 3、逐渐将你的员工融入一个团队中 在第二层次时,员工们喜欢在一起,在第三层次时,员工们开始在一起工作,生产让团队构建成为可能。 团队构建核心: 团队成员应该优势互补: 领导者工作是去构建一个互补型的团队,每一们成员人优点殾能发挥,而每一个缺点都互不相关。 团队成员应当理解其使命 第三层次领导人他时,不要想当然的认为队员清楚你所知道的或者相信你所相信的。 团队成员应该得关于自身表现的反馈 人们总是期望知道自己做的怎么样,如果他们没有成功,大多数据时间里他们期望知道如何做出调整提高自己。 团队成员应该在一个有益于成长并受鼓舞的环境中工作 领导者比其他任何人都能为一个团队、部门或者组织设定基调,他们的态度是具有传染性的。如果你想在第三层次的领导力取胜,认清自己的影响力,并利用其实现人尽其能。 4、将高回报的事情放在前面优先做 有效的优先原则应该从排除那些你不应该做的事情开始。 践行帕累托法则(二八法则) 5、愿意并准备成为一名变革失去者 6、永远不要忽略“成果即目标”这一事实 五、 迈向第四层次的信条 1、仅有生产是不够的 优秀的领导者是以他们的育人能力来衡量自己的,这需要在一个领导力的文化氛围中培养他人。 2、人是一个组织中最宝贵的财富 如果你想要迈向领导力的下一个层次,就应该让自己的思维超越生产的局限,开始思考如何帮忙你团队中的个体提升自我、发挥潜能。 3、培养领导者是实现梦想最有效的途径 如果你想要一个轻松的工作环境,赢得第二层次。如果你想要一个富有生产力的工作环境,赢得第三层次。如果你想要一个成长型的工作环境,赢得第四层次。 4、人的发展与培养是领导者最大的成就 六、 成长指南 以你所期望的团队成员标准来要求自己:人们效仿他们所看到的,如果希望团队成员专注、富有生产和,领导者必须以身作则。 将个人生产能力融入领导力:从个人和团队两个方面,将视野扩展到自己的生产之外的地方,帮忙他人成为高效生产者。 了解每个人的最佳生产领域 持续不断地筑起梦想 建设你的团队:创建一个重视成长与表现的环境。 用动势来解决问题 分辨清楚团队成员如何影响前进动势:最大化引领潮流者,激励顺应潮流者,最小化逆势潮流者。 践行帕累托法则 敢于接受你作为变革推动者的角色:永不停止地探寻团队提升的道路并付诸实施。 不要忽视第二层次
领导力的5个层次-认同 ---爱人者方能御人 一、 前言 当领导者开始学习在认同层面上领导,员工第一次从服从者向追随者转变。人们会比仅仅服从命令付出更多,因为领导者开始用人际关系来影响他人,而非职位。 二、 认同的积极方面(每一位员工都更加热爱自己的工作场所) 1、 人们对于领导力的认同主工作更加令人愉快 职位型领导者更多的是关注于他们自己,很少关注他人。而认同型领导者关注点从“我”转移到“我们”,他们喜欢自己的员工,关心员工所在乎的事情,通过相互交流同员工建立起深厚的人际关系,这种转变对工作环境产生的积极的影响,人们开始彼此喜欢对方,工作场所也为人们更加令人愉快的地方。 2、 人们对于领导力的认同可能增加能量级 与寻些你讨厌的人在一起会消耗你的精力,这种工作环境让大数人不适应。即使与你不熟悉的人一起工作,也需要消耗你大量精力去认识他们、了解他们。相反与喜欢的人在一起总能令人精力充沛。 3、 人们对于领导力的认同为沟通打开了方便之门 在领导力的第二层次,自上而下的职位型领导力为并肩而行的人际关系取代,在认同层面,领导者积极听取员工的意见,员工也听人领导的调遣。 优秀的领导者是开放的,他们积极去接触组织中的各种员工,他们会实现良好的沟通交流(双向交流),建议起一个共同体,人们彼此相知、关心。 4、 人们对于领导力的认同会去关注每一个人的价值 不领导别人你照旧可以关心他们,但是假如不去真心关心他们,你将不可能成为超越第一层次人的高效领导者。 没有任何东西能比受他人尊重与珍视更鼓舞人,第二层次的领导者了解每一个员工的独到之处,学会欣赏他们的与众不同,让他们知道他们很重要。 5、 对领导力的认同结出信任之果 信任是认同的基础,如果你坦诚对人,你就会建立起信任;建立 的信任越深,人际关系就会越牢固;人际关系越牢固,领导者获得员工的认可的潜质就越大。这是一个需要时间、精力和意愿的建设过程。 当危险来临时,人们会自觉地依附到那些他们知道可以信赖的人,那些没有离开而与他们同舟共济的人身边。 三、 认同的消极方面(你要背负起建议良好人际关系的压力) 1、 认同型的领导力对于某些人而言显得过于“软弱” 在一个难以驾驭、高绩效、领导力强化的环境中,通过获得员工的认同来领导对某些人而言或许显得太“软弱”。容易陷入只愿意做令每个人都满意的决策,从来不想去做一些艰难的决定。 大多数人的领导力成长之路不是从生产力这样的“硬”方面开始,就是从人际关系这样的“软”层面入手。从硬方面入手但以拒绝在软技巧上学习突破的人往往会在第一层次卡住,他们想往每三层次发展,但没有经历第二层次上的成长是不可能和的。相反,从软方面起步的领导者很容易成长到第二层次认同层面,但,如果他们只停留在人际关系层次,他们也会停止不前,难以提升到第三层次。优秀的领导者,软与硬都不可或缺。 领导者的任务应该是帮助别人,而不单单是取悦他们。领导都要集中精力去做那些对整个组织与员工最好的事情,让每一个员工都满意不是领导的职责所在,也是不可能做到的。要想扭转“软”层面的不足,需要增加领导力中“硬”(生产力)的方面。 2、 在认同认同层面上的领导他人会使亟待成功者沮丧失望 亟待成功者希望现在就把事情做好且不想为了任何东西放慢前进的脚步,便实现认同层面的领导力恰恰要求他们这么做,建立人际关系是需要时间的。 领导力最基本的目标的:帮助他人、向前迈进并获得成功。 3、 认同型领导者可能会被别人利用 4、 认同型领导力需要行之有效的开放 领导力最关键的品质不是完善无瑕而是值得信赖,人们必须能够去相信你。 认同型领导者如果想要建立起真实可信的人际关系,首先为人要坦荡真实,敢于承认自身的缺点和承担自己的失误,这也恰发与职位型领导者相反。 5、 认同型领导力对于那些“天生不太惹人喜欢的人”有难度 那些不太招人喜欢的人也不太喜欢其他人,他们对其他人的关心程度往往不够。 6、 认同型领导力迫使你去与每个人的方方面面打交道 领导力的核心是与人打交道,与每个人好的、坏的一面打交道。我们对别人了解得越多,或许我们会更失望,每个人都不完美。我们必须学会去接受对方,接着工同工作下去。 共同点或许会让彼此关系更令人愉快,但唯有不同之处地能让彼此关系更加充满乐趣,认同型领导者能够巧妙的处理这些不同之处,并利它们来更好搂团队和组织谋利。 优秀的领导者能够看到员工的缺点,但从不回避问题,而是积极解决他们。以一种仁者与求真的精神直面现实。 四、 最佳行为选择(如何赢得员工的认同) 1、在与他人沟通之前先要了解自己 自我认识—了解自己的长处与弱点,学着让别人来评价你,清楚你自己在各个环境中的所思、所感与所为。 自我形象—-处理好个人问题,这样你就可以以一种积极的方式来看待自己 自我诚信—-无论现实如何残酷,从客观实际的角度审视你自己,并勇于面对现实。 自我完善—-朝着更好的目标虚改变自己,努力提高培养人际关系的能力 自我责任—-明确你要为你自己的行为与态度负责。 2、培养以人为本的领导风格 认同型领导者从偿依赖制度领导他人,他们去倾听、去了解,再去领导。 认同型领导者如果想取得成功,你的思维必须更少的从机制出发,更多的从员工的情绪出发,更多的从人的能力考量。 3、践行黄金法则 你想别人怎样对待你,你就要怎样对待别人。 4、做你团队的主要激励源泉 善言虽短又易说,但回赂却是无穷尽的。人们希望从伙伴中得到肯定,但是他们更加珍惜来自领导者的赞许。 5、努力找到关爱与坦率之间的平衡 没有坦率的关爱会导致不良的人际关系,而没有关爱的坦率则造成人际关系的疏远。唯有蕴藏着坦率的关爱之心才能成就发展中的良好关系。 领导都必须从最大多数人的得益做出最好的决算。因此,领导者应放弃去迎合某个个人的权力,如果这会伤害整个团队或者组织。 五、迈向第三层次的信条 1、单单只凭人际关系是不够的 如果你能和你的团队保持亲和力,那你现在就拥有了些许对他们的影响力,但真正的领导力会将员工带到新的境界,因此他们能够完成一些事情。这需要领导者将员工的潜质与他们的表现连接起来。 2、建立人际关系需要双重的成长 使人际关系的构建变得真正有意义是共同成长,犹如情侣间的感情一样,起初相互吸引建立起了感情,但要让这估关系长久,你需要去延续这段关系,这需要共同成长。 3、为了实现团队的愿景值得拿人际关系来冒一冒险 如果你想成就大事,你需要将员工带离他们的“舒适区”,这或许会失败,但如果成功 了,那么你的员工就会具备自信力,团队也会敢于承担更加艰难的挑战。如果失败了,你会失去与员工的信任关系,从而不得不去重新建立人际关系。 在领导力实践中,风险总是存在的,每当你努力向前迈进时就会存在风险。但是没有风险就没有进步,所以你需要逐渐地适应它。 六、成长指南 确定你对他人持有正确的态度:你有多喜欢你的员工,员工有多喜欢你 认识你自己:自我认识、开解、诚信、完善、责任 知道你是从哪里来的:学习如何同时赢得关系与成果 对你团队的每一个成员表达珍视之间 评估你自己在团队中所处的位置: 你知道这个人工作之外的哪三件事? 这个人认为什么最有价值 这个人前三大关注 点是什么 这个人对于人生有怎么样的希望或欺诈? 尝试对每个员工回答下列问题,如果回答不上来,是时候抽时间去了解这个人了。 6.领导一部分,接受一个下属的全部:不能只利用员工的时间和技能而忽略他的其它部分,担负起帮助他人的责任,处理好领导力复杂的一面。 7.将乐趣作为目标 8.一心一意地去关怀你的员工 9.成为你团队的“首席鼓励者” 10.践行关爱与坦诚:当你看到团队中某些人在犯错误或者不合标准,立即同他们坦诚交流,平衡好关爱与坦诚确保你的行事方式是正确的。
领导力的5个层次-职位 ---你已经踏上了培养领导力的征程 一、 前言 传统意义上的领导力征途都是从领导职位开始的,职位是领导力提升之旅的起点,也是领导力建立与发展的最低层次与牢固基石。真正的影响为必须以此为基础。 二、 职位的积极方面 1、 领导职位被赋予某些人往往是因为他们具有领导潜质 大多数时候人们能够获得某个领导职位,往往是由高层权威人物的任命,同时也意味着高层权威人物认为新任命的领导者具备某种程度的领导潜质。 领导头衔只是提供了一个发挥领导能力的平台,但不能保证所有的队员都能听从你的,赢得团队成员的服从与拥护是新任领导的责任。 在这一层次新任领导有机会表达自己的意愿并做出决策,同时新任领导最首要的目标就是向你的上司和团队证明,你个人能够胜任这份职位。 2、 一个领导职位意味着你的领导权威被认可 当一个人获得领导职位和头衔时,某种程度的权威或者权力会随之而来,尽管最初的权力或许非常有限,但领导者仍需要通过极少权力的运用证明自己以赢取更大的权力。 只有一个人的任命深入团队每们成员心灵的时候,他才是一名真正的领导者。 作为一我新领导者,必须明智地运用被赋予的权威,着眼于帮助你所领导的人与整个团队的提升,只有这样你的追随者会赋予你更大的权威。此时,你所赢得的是领导力,而不仅仅是一个职位。 3、 领导职位是促使领导者成长的催化剂 获得领导职位与肩负领导职责是密不可分的,其中最重要的一项要求是领导者的个人成长,只有你在领导力征程上不断求索、坚持不懈,你最终才能取得成功。 如果你想要领导别人,首先要成就自我,提升一个组织的唯一途径就是培养组织的领导者,如果想有所作为,首先从你自己开始,优秀的领导者总会是优秀的学习者。 4、 一个领导职位使得潜在的领导者能够定义与塑造自身领导力 人们被赋予一个领导职位最大的潜在优势在于为他们提供了一个机会来决定他们想要成为哪一种领导者。他们所获得的职位或许已被界定,但是他们本身不是。 新任领导者的履历上是空白,你可以随心所欲地去描绘它,只要你的领导风格与你的为人相符,你就可以建立起你所想要任何领导方式。 思考你所要建立的领导力风格?重点(P34) 三、 职位的消极方面 1、 拥有一个领导职位常常带有误导性 职位是定义领导力简单的方式,一旦你拥有职位或者头衔,人们会把你等同于它。但拥有职位不代表你已经成为真正的领导者,我们应该将职位视为一个成长为领导者的机遇。 领导者总是在将人们带向前方,他们不是静态的。 2、 依靠职位的领导者常常低估人的价值 依靠职位来实现自身领导力的人总会将他们的职位赋予极高的价值,对他们而言职位比工作、团队成员都重要。这种态度对于促进良好的人际关系寻建立有害无益。 职位型领导者往往将员工视为麻烦制造者,或者可以任意替换的工具,甚至是他们实现下一个职位晋升目标路上的制造麻烦的障碍,从而导致团队士气低落。依靠职位去影响他人的领导者往往也难以与人良好合作。 职位型领导者为了使自己的开形象更佳或者防止其他人成长起一威胁其地位,他们往往会让其它人自我感觉渺小。 职位型领导者在领导人时忽略了人的因素。人都是有希望、梦想愿望和目标的,领导者必须把他们自身的理念与员工的志向以一种共赢的方式结合起来。 任何类型的领导力都是与人合作的学问。 3、 职位型领导者依赖于政治手段 职位型领导者更加关注控制力而非奉献。 4、 职位型领导者将权力置于责任之上 职位型领导者会产生强烈的权力意识,他们期望员工服务于自己,而且去服务员工。他们将权力置于团队合作之上且忽略人际关系,这对于 团队合作、创建积极的工作环境毫无作用。 仅仅因为你作为领导者有权力去做某事,并不意味着那是一件正确的事怀。把你的注意焦点从权力转变为责任往往是一名领导者走向成熟的标志。 领导者必须努力成长为不依赖于自身职位的领导角色,我们要把焦点从为自身利益享受权威转变为用自身权力去服务他人。 5、 职位型领导者往往是孤独的 职位型领导者如果错误的理解领导力的作用和目的,他们很容易变得孤独。优秀的领导者是要与员工并肩同行,并帮助他们和你一起攀登高峰。 如果只是你自己一个人居于山峰高处,你或许就会觉得孤单。如果有其他的同伴在你身边,你就不会觉得孤单。 领导者并不必然孤独,那些三到孤独的人其实是自己一手造成的。 6、 职位型领导者会被打上标签而难以前行 当人们利用职位来长期领导他人并且难以建立真正的影响力时,他们就会被贴上职位型领导者标签。依赖职位越久,想要改变别人对你领导方式的因有印象越难。 努力为新领导者创造成功的条件,为此有经验的领导者可以提供领导职位、时间(与有经验的领导者沟通交谈)、个人影响力、亲身示范、各种资源以及领导力的各种机遇帮忙他们成为一名成熟的领导者。 7、 职位型领导氛围下员工流动率会很高 人辞退人,而非公司 停留在领导力第一层次的组织倾向于流失第一流的人才,而只能吸引到二流甚至三流人才。因为优秀的领导者会离开一个能力较差的低层领导者,同时,低层次的领导者会想方设法把高层次的员工排挤出去。 8、 职位型领导者用人之弱,而非其强 职位型领导者往往付出最少,而期待他们的领导职位为他们努力工作,结果就是员工也付出最少。 当为你工作的员工几乎迫不及待地要离开自己的工作岗位时,的确某些方面出了问题。 员工不会为他们最不喜欢的领导者付出最大的努力。 成功需要绝大多数人的甘于付出,但敢不会超出他们的能力范围。使事情变得与众不同就是优秀的领导力。 四、 最佳行为选择 1、 不再依靠职位来强迫别人 最顶尖的领导者从不用自身职位来达到成事的目的,而是运用其它技能来影响他人的行动。 为了帮忙新领导者了解这一课,可以在赋予潜在领导者领导职位之前让他们开始领导别人,即给予潜在领导者责任而没有头衔也不告诉别人他将会在为领导者。新的领导者必须学会如何在没有头衔或职位权威的情况下提升团队的表现。 2、 用授权换来前进 领导力不是一项权力,而是一种殊荣,需要不断地去努力获取。 优秀的领导者从任何东西都视为理所当然,领导力必须赢取并建立且不满足于现状。 组织财政部可以充满规章制度,但团队的构建可以仅依靠做么的领导力。 3、 离开高高在上的职位,走到员工中间去 依赖职位的人往往会错误地认为员应该主动前来满足他们的所需与所想,优秀的领导者认为走到员工中间去是他们的责任,领导者也应成为倡议者。 要想推动世界,先自己行动。 五、 迈向第二层次的信条 1、 头衔是不够的 头衔所拥有的实际价值很小,职位也只是领导力的第一层次。 工作本身以及由此产生的对他人的积极影响才是最令人满意的奖励。 职位并不是值得所有人去追求的人生目标,所谓的安全感不能成国最终的目的。 2、 人脉,而非职位,是一个领导者最宝贵的财富 现实是由人来完成各项任务,而不是他们使用的工具,人是任何组织背后的力量,因此他们是最富有价值也是最有升值潜力的资产。 3、 领导者并不一定需要知道所有的答案 我们中第一个人的聪明才知都不及团队的智慧,领导者不用装作无所不知,做回自己,同时学会驾驭集体智慧的的力量。 领导者的职责不是无所不知,而是能够把那些能“知你所不知”的人才吸引到麾下。 4、 一位优秀的领导者总是会包容他人 领导力提升之路都是与他人相关的,你要与别人有良好 的人际关系,也要求你以身作则,培养并武装别人。 优秀的领导力是与他人一起领导,而不仅仅是领导他人。 六、 成长指南 感谢那些将你带进领导力旅程的人 致力于领导力成长的终生追求 定义你自己的领导力 实现从职位到潜能的转变 重点关注你的愿景 实现从规章制度到人际关系的转变 主动地同你的团队成员联系 不要总是提及你的职位或者头衔 学会说“我不知道” 寻找一位领导力教练
领导力的5个层次概述 【领导力定义】 本书作者对领导的定义是“领导力就是影响力”,在作者的另一本书《中层领导力:自我修行篇》中,作者又说:“领导力是拥有追随者的能力”。一旦明确了领导力的定义是拥有追随者的能力,你就要参考这一点弄清楚如何去领导他人、引导他人。 罗伯特.戴伦在他的《Power and influence》一书中分享的“铁三角”理念将帮忙领导者站在最前沿并获得成功,罗伯特说道:“这个三角形的三点分别是沟通、认可和影响。在进行了有效的沟通后,接下来就会得到认可,随之而来便会产生影响力。” 随着人们对于身边其他人影响力的与日俱增,他们就能更加有效地领导他人,领导力的动作机理框架正是领导力的5个层次。 【领导力的5个层次概述】 第一层次——职位 职位型是领导力中最初级的境界,即所谓”入门层次”。职位型领导者所仅有的影响力来源于他的职位头衔。拥有一个领导职位本身并无可厚非,但是将其作为迫使员工服从自己的筹码则是大错特错的,依靠职位换取影响力实非高明之举。 职位型领导很难称得上真正的领袖。此类领导依靠各种规章制度来管控他们的员工,这样的后果是员工只会在领导者权威所及的范围内服从他们,以完成“分内事”为已任,而领导者于其权力范围之外,则很难要求员工付出额外的时间或精力。 职位型领导在与志愿者、高素质员工相片时,也往往存在困难,因为这类员工具有理工加强烈的独立倾向,仅仅靠职位难以对其施加充分的影响力。 职位型领导力也是唯一不需要能力或者努力就能得到的,只要被赋予某个职位就自然地会拥有它。 第二层次——认同 领导力的第二层次完全基于对人际关系的把握,此时领导者的着眼点已非维持自己的职位,而在于如何去了解身边的人并努力探寻和他们的相处之道。 领导者与追随者彼此了解,建立起牢固持久的友好有关系,同时在这个过程中信任得以建立,工作环境都会变得积极向上。 即使没有领导他人,你也可以喜欢他们,但如果不能真正关爱他人,你却很难领导好分们。 第三层次——生产 真正优秀有领导者并非只是营造一个舒适的工作环境,他们更能把任务完成,工作做好!这一领导力层次是基于成果,领导者由此获得影响力和公信力。人们开始追随领导者是因为他们对于整个组织的巨大付出,即你能做什么! 第三层次的领导能够勇敢面对并及时解决棘手的难题,做出艰难的抉择挽回困局,能够将追随者引领到新的高校境界。 第四层次——个人发展 第四层次的领导,他们善于授权。 他们充分运用自身的职位权力、人脉关系和生产能力投资于他们的追随者,着力培养他们直到他们真正成长为新的领导者,关注个人发展层面的领导者实际上在不断复制他们自己。 在这一层次,团队协作迈向新的水平,因为对于人力资本的投资加深了人际关系,帮助人们增进相互了解与忠诚度。同时,由于团队中更多领导者的出现促使他们帮助更多的人提升工作质量,工作表现也迈上新台阶。 这个层次的领导者改变了他们追随者的人生,人们之所以追随你是因为你对他们的个人的付出,这种情况下结成的人际关系往往是终生的。 第五层次——领袖特质 领导力最高的层次,大多数人能够实现从第一层次向第四层次跨越,但第五层次所需要的不仅仅是努力、技能和意向,某种程度上也需要具备高水平的天赋。 巅峰领导者致力于培养实现第四层次的领导者。在所有领导力任务中,难度最大的就是将领导者培养成能够并愿意增培养其它领导的人。 【领导力的5个层次的深层视角】 你可以成功迈向领导力的下一层次,但你的足迹会留下永恒的印记 对于不同的人而言,你并不是总在同一领导力层次上 你的领导力层次越高,领导力的实现就越容易 你的领导层次越高,越需要花费更多时间与精力去再上新台阶 领导力征程上每提升一层次都是需要日程月累的,而后退却是瞬间可成的 迈出的步伐越远,回报越大 工欲善其事,必先利其器 在某一领导力层次上的固步自封会限制你和你的团队 当你变换职位或组织时,你基本上要从新的领导力层次开始 你不能够独自走在领导力攀登的路上
当人们被提升到第一个领导岗位时,他们常常认为自己有成功的把握。作为业绩出色的员工,他们的努力得到了认可和回报。实际上,第一次担任经理要想获得成功需要一个重大的转变,即他们的工作成果不再是通过自己亲自做去获得,而是通过下属和团队的努力去获得。 领导者必须意识到,在职业发展方面,今天的大多数员工知道真正的工作保障是具备生存的技能,清楚自己的职业发展路径,他们渴望职业发展机会。一线经理需要顺应这些新的形势,虽然他们大多是业务或技术出身,擅长利用专业技能完成任务,但他们并不熟悉如何了解和满足员工需要和期望。他们需要认识到第一层级领导工作的特点,下表概述了这一层必须经过的转型: 如上图所示,转型既有工作内容的变化,也有工作性质的变化。管理者必须停止考虑自己,把精力放到关注他人的团队上。转型可以概括为以下三个方面: 界定和布置工作:包括与上司、员工沟通,需要他们做什么,以及工作计划和设计、组织结构、人员选拔和工作制授权。 提高下属胜任能力:通过监督、指导、反馈、获取资源、解决问题和交流沟通提高胜任能力,从而高效开展工作。 构建合作关系:建立与下属、上司和相关部门坦率交流与相互信任的合作关系 领导力在第一个管理层级出现问题的明确信号是员工感到压力很大,不知所措,甚至抱怨上级没有足够的支持。 如下迹象表明经理缺乏岗位所需的关键技能: 把下属提出的问题看成是障碍 补救下属的工作失误,而不是教会他们如何正确的去做。 拒绝与下属分享成功,对他们的问题和失败避而远之。 要帮助员工就要关注他们,看他们在做会么,如何做的。经理需要定期与员沟通,并密切关注工作流程的执行情况,要询问是什么阻碍了工作完成,什么促进了工作完成。 监督是一项主动而非被动的工作,当结果与期望一致时,就应当给予员工适当鼓励,同时给予积极的反馈意见。当结果令人失望时,应通过监督获得的信息进行计划调整、方法调整、加强培训,以及要求增加更多的资源支持等措施,让工作回到良性发展的轨道。 疏通梯队战术 初任经理要实现顺利地转型,需要有效的方法帮助他们为转型做好准备,观察他们是否成功转型,支持他们克服转型中出现在问题。 方法一,准备: 让初任经理清楚地知道新岗位的要求,包括领导技能、时间管理能力和工作理念,并为他们的实现转型提供必要的培训。 方法二,监督: 确认初任经理在转型中是否遇到了困难,困难是什么。具体评估是否转型成功方法如下: 观察:旁听初任经理与下属的沟通,看看他们是否展现出必要的领导技能。 抽样调查:通过360度评估(评估以上的领导特质)、员工态度调查和其它评估工具,了解他人如何评价初任经理的行为和态度。 差距分析:询问初任经理对自己的领导技能、时间管理能力和工作理念的看法。将这个结果与前面的观察、抽样调查进行比较分析,让他们知道三者之间的差距。 方法三,干预: 定期提供反馈和教练辅导,帮忙初任经理实现转型。如果他们遇到困难,就采取措施帮忙解决。上司需要采取某种程度的行动加速初任经理的转型,而不是任凭他们沿袭作为个人贡献者时的行为和态度。 教练辅导与反馈:一对一教练辅导,沟通听取问题并给出建议。 向同事学习,增强合作:组织经理人员相互交流领导技能,交换工作思路和感受,探讨共同问题。向标杆学习也是一种有效的办法。 会议、读书和旅行: 初任经理从自己视角主动录求转型,在会议上谈论自己学习的收获,加深对自己转型的认知。 工作调整:初任经理首先需要实践并完善他们 领导技能,学会有效分析时间转变工作理念。 衡量领导力的指标: 团队工作效率、工作产出、员工能力发展等。
本书中提出的领导力发展的六个阶段模型成为企业领导力开发的经典指南。通过对六个典型管理层级经常出现的问题,从领导技能、时间管理能力、工作理念三个方面进行了分析,提出了改进建议。 【问题与现状】 当前企业在领导梯队建设方面存在四问题: 第一类:”临时抱佛脚”,平时重视不够,投入不足,一旦机遇来临常常错失成长良机。 第二类:”无从下手”,领导虽然重视,但人才培养观念落后,缺乏系统,方法欠佳,收效甚微。 第三类:”拔苗助长”,常常”士兵当排长用,排长当连长用,连长当团长用”,导致人岗错配,管理问题导出不穷。 第四类:”重事轻人”,企业过于重视领导人才的业务能力,忽略了他们带队伍的能力,忘记了”领导力就是通过他人去完成任务的学问”。即使担任领导职务,仍然是”业务员思维”,凡事亲力亲为,不善于识人用人、授权赋能、激励人心,不能培养出优秀的下属,只能贡黄贡献业绩,不能贡献人才。 【领导梯队模型】 领导梯队模型由是数条上升的折线构成的图形(如下图),每个转折点都代表了公司职位的变化---在领导层级和领导为复杂程度方面(包括新岗位的工作要求以有新的领导技能、时间管理能力和工作理念)。 注:每个阶段都代表领导者在工作要求上的重要变化,包括新的领导技能、时间管理能力和工作理念。 【领导梯队各个阶段】 第一阶段:从管理自我到管理他人,重点是从自己做事转变为带队伍做事(工作理念)。 第二阶段:从管理他人到管理经理人员,关键的领导技能是教练选拔人才担任一线经理。 第三阶段:从管理经理人员到管理职能部门,需要学会新的沟通技巧以跨越两个层级与员工进行沟通。此外,还必须管理自身专业以外的其他工作,这意味着他们必须懂得专业以外的工作且必须学会评估它的价值。 第四个阶段:从管理职能部门到事业部部经理,重点是转变思维方式,从赢利和长远发展的角度评估计划和方案。 第五阶段:从事业部总经理到集团高管,必须擅长评估资金调拨和人员配置的战略规划、评估业务的投资组合策略。 第六阶段:从集团高管到首席执行管,必须具备重视外部关系的视角。转变更多人集中在经营理念而不是管理方面。 每个阶段都要求领导者习得一种新的管理和领导方法,同时抛弃原有的访求。主要表在以下三个方面: 领导技能------胜任新职务所需要的新能力 新的时间分配结构,决定如何工作 信念和价值观非常重要,让工作聚集
转自:http://36kr.com/p/5047953.html 编者按:本文首发于微信公众号“iOS开发”(ID:iosDevTips),内容总结于《格鲁夫给经理人的第一课》,作者唐巧,授权36氪发布。 前方高能提示:本文特别特别长。我总结本文花了将近一个月,如果你在经历从技术到管理的转型,那么本文值得你仔细阅读。我从本书中收获巨大,希望你能从这篇总结中也有所收获。 本书的作者格鲁夫是一个技术出身的管理者,在本书中,我们甚至看到他多次用编译器来举例,所以这本书非常适合有技术背景的读者。 《格鲁夫给经理人的第一课》最早出版于 2007 年,书原名为《High Output Management》。本书的作者格鲁夫是 Intel 的前 CEO,领导了 Intel 从一家濒临倒闭的存储器公司,转型为微处理器公司,并且在个人 PC 开始流行时,成功和微软缔结 Wintel 联盟,主宰了整个 PC 电脑时代。 本书主要分为四大部分: 第一部分「早餐店的生产线」:用早餐店的经营故事,来类比企业的经营管理,介绍了一些数据分析、产品预测、产品检验的办法,提出了管理杠杆率以及关注于产出的管理原则。 第二部分「打好团体战」:展开论述管理杠杆率,并且讨论了开会、决策和规划。 第三部分「推动组织的巧手」:从企业组织架构入手,谈混合型组织,双重报告,CUA 模型,以及文化价值观。 第四部分「谋事在人」:讲人员管理。涉及激励、工作成熟度、绩效评估、招人与留人、报酬与培训。 第一部分:早餐店的生产线 本部分用早餐店的经营故事,来类比企业的经营管理。介绍了一些数据分析、产品预测、产品检验的办法。 第一章:“生产” 包含什么? 格鲁夫认为,一个早餐店的生产线,就包含了一个现代软件开发管理中的各种问题。一个合格的早餐店的生产线,可以在预定的时间内,用最低的成本,做出顾客需要的产品。而现代软件的开发流程,也是希望在一个预定的时间内,用最低的成本,开发出符合产品经理定义的、合格的应用或服务。 这个过程,涉及一些最基本的项目管理工作:找出限制步骤,然后优化流程,形成一个最佳的策略。 在经营早餐店的故事中,限制步骤可能是人员数量、一些机器的产能、或者库存量。通过分析这些限制步骤的成本和收益,你就可以找出一个最价收益的方案。 软件开发中的项目管理也是这样,你的限制步骤可能是人员数量、开发时间、产品功能点、测试时间、或者技术实现方案。找到限制步骤后,通过优化限制步骤就可以优化整个流程。 第二章:从早餐店的库存谈起 格鲁夫认为,我们应该确定和监控早餐店的核心指标,对于一个早餐店来说,核心指标包括:销售预测、原料库存、设备状况、人员情况、品牌评价(用户反馈),并且每天检视这些指标。 另外,作者提到,指标应该有相互的限制,这样避免过度反应。就像软件开发中的软件质量与开发时间一样,不能只追求质量而不管开发时间,也不能只追求时间还不管质量。 其实作者在这章强调的就是数据分析的重要性,在数据分析上,作者介绍了一些方法,包括: 先行指标,用于揭示未来信息的指标,例如 NPS,机器故障记录。 线性指标,用于分析进度的指标。 趋势指标,用于分析变化趋势的指标。 重复印证表,用于修正预测行为,提高预测准备性的指标。 作者接着提到了计划生产。这个事情是预期未来的销售额而提前生产(放到库存)的一种行为。这里面合理地预测未来是核心,否则要么就会造成没有商品可卖,要么就会造成库存过高。刚刚提到的「重复印证表」可以比较好地帮助我们做预测的调整。 作者接着提到了检验质量。检验质量应该在生产的每个环节都做,但是越早的环节,检验的成本越低。就像我们修复程序的 Bug 这件事情一样,如果我们刚刚写完代码就收到相应的 Bug 报告,那么修复的成本会小很多。但如果我们写完过了一周才收到 Bug 报告,那么我们就需要花精力先回顾当时的逻辑,才能进一步找到有问题的代码。 作者提到了一些检验质量的办法,用于节省检验本身的精力成本。 第一种检验办法是:海关与监视器。海关简单来说就是所有的东西都必须检查,监视器简单来说就是抽样检查。根据具体产品出问题的概率,以及出问题的危害程度,我们可以结合海关的检验方法和监视器的检验方法。 第二种检验办法是:随机检验。随机检验的量应该随着检验结果的好坏有所调整,使得检验有针对性。 本章的最后,作者提出了管理杠杆率的概念,并且用下面的漫画来做了解释。作者认为,通过定义管理的「产出」,我们可以专注于那些提高产出的管理活动,那些高投入产出比的管理活动被作者称作「管理杠杆率」高,进而应该被优先安排和执行。 第二部分:打好团体战 本部分介绍了管理的一些经验技巧,涉及管理杠杆率、开会、决策和规划。 第三章:管理杠杆率 作者首先在本章定义了经理人的产出: 经理人的产出 = 他直接管辖部门的产出 + 他间接影响所及部门的产出 格鲁夫介绍了他一天的工作,能够看出来工作内容非常杂乱,也非常多,而且做不完。他说: 我的一天通常结束在我觉得累而决定回家休息的时候,而不是事情做完了。 像家庭主妇一样,经理人永远有忙不完的事情。 因为事情永远做不完,所以我们更需要关注于工作的产出,把最高优先级的事情找出来优先安排和执行。 1、管理工作的分类 我们从格鲁夫一天工作的介绍中,能看出来他的工作分为几类: 信息收集类。看邮件、看报告、开会、和同事聊天、看用户反馈、看产品数据、试用公司产品等。 传递信息。培训或者分享观点。 决策。通过、制定或者否决一些方案。 给予提示。传递一些观点。 为人表率。提供行为示范。 在信息收集方面,作者鼓励在使用传统的邮件和口头直接沟通外,多增加一些非正式的沟通机会。比如多随意在公司里走走,找不同的人聊聊天等等。 在决策方面。作者认为决策分为两类:「未雨绸缪型」和「亡羊补牢型」,前者是在规划未来,后者是在补救当前问题。 关于给予提示,作者认为他与决策的差别在于,给予提示很多时候并没有明确的方案,他是希望让对方通过提示来做一些调整,而调整的具体的细节需要对方自己思考。 除了以上四类(信息收集、信息传递、决策、给予提示)工作,作者也提到,管理者的所有行为,同时也在以「榜样」的作用被员工效仿。例如管理者随意迟到,员工就会随意迟到。管理者做事情认真,员工也会有认真工作的压力。 2、管理杠杆率 在介绍完管理工作的分类后,格鲁夫给大家介绍了他的管理杠杆率公式: 经理人的产出= 组织产出的总和= 杠杆率 A 管理活动 A + 杠杆率 B 管理活动 B …… 与管理杠杆率相关的因素有很多,包括时效:一个员工有离职情绪时,及时沟通的时效就很重要。一个重要会议要开时,提前准备内容的时效就很重要。 另外,格鲁夫指出,也有很多管理活动的杠杆率是负的,例如:经理人情绪低下,影响员工士气。经理人越权干涉别人的工作,影响别人积极主动性。经理人做出错误决策,浪费人力物力。 格鲁夫指出,高杠杆率的事情包括: 当一个经理人可以同时影响多个人的事情 当经理人一个简单动作或简短谈话,会对别人产生长远影响的时候 当经理人的技术、知识或信息,对一群人造成影响的时候 作者也列出了一些具体的高杠杆率的事情: 关注用户的反馈,特别是抱怨。 绩效评估。 传授知识、技能或价值观给部署。 授权。 3、授权 关于授权,作者做了展开的介绍: 没有完备监督计划的授权等于渎职。你绝对不能完全地抽身,即使你已经授权,你还是得负成败责任。全程监督整个被授权的案子是确保结果尽如人意的唯一方法。监督不是干涉,而是通过不时的检查,来确定活动的进行一如预期。因为监督你熟悉的工作比较容易,所以如果有机会,你应该把自己熟悉的工作授权给他人。但切记先前举的例子—理智叫你松手,但情感上你可能老大不愿意。 监督的办法可以用上一部分提到的检验产品质量的原则:越早检验成本越小。例如对开发工作不熟悉的员工,让他们在写代码前就先给你讲讲他打算如何规划,就比让他写完你再检查要好得多。 监督的另外一个技巧也是检验产品质量的原则提到的:注意检验的频率。对于新人,要增加频率。对于信任的人,可以降低频率。另外,监督的方法要具有多样性,对不同的人采用不同的方法。 监督并不是说经理人一定需要替员工考虑好事情的方方面面,因为这毕竟需要付出大量的精力。对于某些事情,经理人只需要提出一些细节问题来测试员工的思考是否全面,则可以一定程度上评估出事情的靠谱程度。对于经理人不熟悉的领域,也可以用此办法。 关于这方面的知识,我在指导 iOS 开发新人的时候体会很深。通常指导新人的常用办法,就是将自己熟悉的工作交给新人完成。因为这些工作非常好通过监督(Code Review + 定期讨论)来保证质量,所以风险可控,而我自己也会从中学习到指导别人的各种技巧和经验。 最重要地,我需要打破我的舒适区,因为我需要放弃自己非常熟悉的工作内容,转而做一些新的陌生的事情。而新人的代码质量和编写速度往往是比我自己直接写要慢得多的,我需要有耐心地等待他们犯错,然后通过 Code Review 和讨论来让他们学习到相应的编程知识。 学会指导新人通常是一个有经验的程序员转向更高职位的第一个挑战,不管是他是转向偏管理的岗位还是继续在技术岗位上深挖,都需要先将手中的工作交出去,才能够承担更重要,更有挑战的事情。 提高效率 作者提出了一些提高效率的办法: 找出限制步骤:重要的、紧急的事情优先安排。这样的情况下有空余,再安排别的事情。 类似的工作放在一起做。例如将邮件处理,QQ 信息回复的事情稍做积累再统一回复。 安排好日程表。对一些事情说不,对日程表的事情留上 Buffer。 建立指标。尽量估计自己在每件事情上的花费,尽管这件事情很难,也可能不太准,但是总是会有所帮助,而且有经验了之后,估计时间会越来越准。 存货法。留一些重要不紧急的事情,使自己不太忙的时候,可以做这些事。比如对于我来说,学习产品知识,试用各种 App 的功能,分析各种 UI 设计就是一个「存货」。 标准化。对一些经常做的事情,制定标准化的流程就可以提高效率。这就类似我们制定的产品评审流程,上线流程一样。标准化了之后,就不用每次想应该怎么做了,按步就班地开展即可。 老被人打断怎么办?作者认为「躲起来让人找不出」或者「叫别人不要在某些时段打扰」的办法都不太好,他介绍了很多有用的办法,包括: 标准化。把一些常见的问题归类总结。如果一类问题有归类总结了,也就意味着它能够被授权给员工来处理了,也很容易被进一步用于员工指导别人。 类似的工作放在一起做。每天固定时间处理员工的问题,或者固定在一对一沟通中处理相关问题。 运用指标。有指标就可以改进流程。看看自己花费在解决临时问题上的时间以及常见问题,然后就可以看看能够优化这些时间。 第四章:管理必经之路:开会 格鲁夫将会议分为两类:过程导向会议和任务导向会议。 过程导向会议:关于知识技能和信息交流,通常是例行的。 任务导向会议:会产生决策的,通常不是例行的。 1、过程导向会议 过程导向会议又可分为以下三类:一对一会议、部门会议,以及运营总结会议。过程导向会议要尽量规律化。 关于一对一会议,我之前专门写过文章:《浅析一对一沟通》。(参考见文末) 关于部门会议,作者的经验是经理人要注意大家讨论的主题和效率,事先讨论的主题需要明确,最好大家在开会前能做好准备。经理人要尽量让讨论是自由的,避免成为自己主宰的「一言堂」。部门会议的议题应该尽量让部属来负责,经理人的责任只是保证讨论不要偏题即可。 运营总结会议是让那些通常没有机会开部门会议的同事提供互动的机会,让他们有机会彼此学习及分享经验。 2、任务导向会议 过程导向的会议一般有固定的开会时间和频率,其效果也多是交流信息为主。而任务导向会议一般没有固定的开会时间和频率,会议结束后一般也需要产出一份会议的讨论结果用于后续执行。 这种需要决策的会议通常需要控制人数,如果超过 8 个人,很可能比较难以推动达成意见的一致。 3、互联网公司实际的情况 就我的感受,互联网公司其实为了追求效率,还是希望尽量少开会,我参与的会议主要分几类: Scrum 相关的会议:包括计划会议、每日站会、评审会议和回顾会议。我们的技术和产品工作都用 Scrum 的方式来管理。 过稿会议:产品的过稿会议,UI 稿的过稿会议。 一些临时性的,需要讨论的会议,类似格鲁夫提到的任务导向会议。 如果把一对一沟通算作会议,那么这也是我常参与的。但是因为一对一沟通的场地经常是在非办公室的区域,所以我其实不觉得这是一种会议。 第五章 不挥舞权杖的决策 由于在互联网公司,科技类知识更新速度非常快,而相对于一线的技术人员,管理者并不能拥有更多决策所需要的专业知识,因此我们需要将具体的决策,下放到一线的员工手中。 格鲁夫在书中描述了一种理想的决策方式: 先是充分地讨论和表达意见 然后是在意见充分被表达之后的决策 最后是一旦最后决策产生,那些少数不同意的同事,都应该在之后执行过程中全力支持。 第六章 规划是为了明天 在你规划行动方案之前,一定记得先问自己:有什么事情我如果 “今天” 做了,可以让 “明天” 更好,或者至少让 “明天” 不会更糟。 在本章,格鲁夫首先介绍了 Intel 在流程规划上的一些方法,但是个人感觉比较偏制造业,因为讲的都是处理原材料,库存与订单之单的矛盾。 接着,格鲁夫介绍了目标管理,包括需要做到:1、有明确的目标。2、有向目标前进的具体方案。 当你将计划落实为白纸黑字时,看起来最抽象笼统的总结即为你的战略,而你用来实行战略的行动即为战术。 对于这章,我自己倒是有一些总结。就我在互联网公司的经验来说,我们做规划和目标管理主要是分为以下几类:产品规划、开发规划、运营规划、人员规划。 1、产品的规划 我们通常需要计划出未来至少 3 个版本的产品迭代计划。然后,对于这些产品计划,安排相应的产品 PRD 稿的撰写和评审、UI 稿的制作和评审、技术评审、开发测试及最后的上线。 2、开发的规划 开发的规划主要是通过 Scrum,将产品和美术稿已经 Ready 的待做事项以 backlogs 的方式放在 Scrum 的管理中。然后在每一个迭代冲刺(Sprint)中,我们从 backlog 里面选取部分工作到当个 Sprint 中。 每一个 Sprint 是包括完整的开发和测试工作,服务器端通常在 Sprint 快结束时,就需要完成上线操作。客户端由于版本发布过于频繁对于用户也有一些打扰,所以我们通常两周对外发布一次版本。 3、运营的规划 大型的运营活动如果需要产品和开发的介入,就也需要相应的规划。通常情况下,我们认为提前一个半月开始是相对充裕的方式。运营花大概两周做活动的策划,剩下的一个月用于技术的排期。 4、人员的规划 作为团队管理者,我们还需要在人员上做相应的规划。这包括: 人员的招聘。预估未来业务增长对于人力的需求,以便提前做好相应的招聘工作。 人员的培养。新人的培养、重要岗位人员的培养。 人员的激励或开除。对一些表现优秀的人员,给予更多的关注和沟通。对一些表现不佳的人员,除了需要明确地指出他们的问题外,也需要根据改进情况选择后续的处理方案。 第三部分:推动组织的巧手 本部分介绍一些实践经验,作者从早餐店的发展作为故事,引出企业管理中涉及的混合型组织架构,从这种架构带来的问题出发,提出了双重报告这种解决方案,由从双重报告需要的企业文化出发,介绍了影响人们行为的 CUA 模型,最后得出高 CUA 因素的工作,需要员工用文化价值观来指导行为。 比较可惜的是,对于如何增强大家的文化价值观,格鲁夫并没有展开讨论,只是说领导应该以身作则。 第七章 当早餐店开始繁衍 在实务中,这种有关管理上集权及分权的分歧到处可见,几已成为今日管理上最重要的课题之一。 本章只讲了一个故事,当早餐店做得越来越好时,分店越来越多,带来的管理上的复杂度也越来越大。不管是采购,还是人事,还是资产,我们都需要专门雇佣人员来负责。 但是除了这个故事外,本章并没有涉及任何解决方案的内容。 第八章 混血型组织 斯隆总结他在通用汽车数十年的经验时说:好的经营管理,是中央集权和地方分权间的折中产品。 本章讨论了两种组织形式:「任务导向组织」和「功能导向组织」。 任务导向组织是以具体的完成某件事情为目标而形成的组织。功能导向组织是以完成某个细分功能而形成的组织。这两种组织各有优缺点,很多时候需要以混合的形式存在于一家公司,而具体如何混合,在不同的公司差异相当大。 拿互联网公司来举例,我所在的猿题库是更偏向「任务导向组织」的公司,我们公司旗下有三款产品:猿辅导、猿题库、小猿搜题。这三个产品下面,各种有着完整并且独立的运营、产品、开发、测试、UI 团队。而我之前工作的网易有道,就是一家更偏向「功能导向组织」的互联网公司,因为在网易有道,有着全公司统一的测试团队、UI 团队。还有一些公司,他们甚至将全公司的移动端开发都集中成一个移动开发团队。 两种组织方式各有优缺点,我们来看看作者格鲁夫的分析。 1、功能导向组织 「功能导向组织」的部门更像是内部的分包商,相比外部的外包商,内部的分包商因为同属于一家公司,所以提供的服务会更好,而且还有: 规模经济。以运维为例,全公司统一的运维部门,有利于在公司内部建一统一的运维规范和运维系统,节省运维成本。 根据需求,转移或分配企业资源。以测试为例,全公司统一的测试团队,在某些产品有更多临时测试需求时,更好地调配人员。 共享知识。全公司统一的测试团队、UI 团队有利于他们更加方便地交流相关的专业技术,测试团队可能在测试流程上更加优化,UI 团队可能在全公司范围内统一 UI 设计规范和准则。 但是,「功能导向组织」的缺点也很明显,包括: 不同部门之间会争抢「功能导向组织」的资源。比如测试团队如果是公共的话,每个部门都会为自己的产品争取尽量多的测试资源,但是谁能够证明自己的优先级肯定比别人的高呢?所以这其中会产生更多的沟通和决策成本。 责任心减弱。这一条并不是格鲁夫总结的,而是我自己感受到的。拿移动开发团队举例,如果移动开发团队是「功能导向组织」,那么某个移动开发者对于一个临时的开发工作很可能并不能做到付出 100% 的全力,因为他很可能只在这个项目做两个月。那么他很可能着眼于「把当前的工作做完」,而不是「整个产品本身的利益」来考虑问题。 举一个具体的例子,当一个产品设计对一种特殊情况考虑不完整时,一个「功能导向组织」的开发者很可能基于按时「把当前的工作做完」这个目标,而选择忽视这些未定义的产品细节,按照「怎么方便就怎么开发」的方式来做,因为产品没定义清楚本来是产品的责任,与他无关。如果他找产品讨论这些细节,很可能使得实现方案变得更加复杂,对于他「把当前的工作做完」这个目标产生冲突。 但是,如果是一个「任务导向组织」的开发者,因为他会长久地负责这个项目的开发,这个项目的好坏最终会决定大家的绩效,他当前没有处理好这个产品细节,以后很可能也会是他来再次重构相应的代码。那么他就有更大的可能去和产品沟通和协调,确定这些未定义的产品细节。 2、任务导向组织 「任务导向组织」的优点是什么呢?优点是需求更加明确,决策更加灵活,人员也更加有凝聚力。 「任务导向组织」也有缺点,主要是这种方式会使得大家在共享专业知识上更加困难。对此,我们公司增加了很多全公司范围内的技术分享会,通过这些分享活动,我们希望增加大家在技术上的交流。 那么,猿题库公司的具体混合型组织是什么样的呢?我们的「功能导向组织」仅包括:运维团队、算法研究团队、数据分析团队、财务和行政团队。而我们将产品、运营、测试、客户端开发、Web 前端开发、UI 设计人员都分拆放到了「任务导向组织」中,而我们按产品将「任务导向组织」分为了三个:猿辅导团队、猿题库团队、小猿搜题团队。 第九章 双重报告 格鲁夫在本章中,推荐用双重报告来解决混合型组织的管理问题。混合型组织中,一个人如果在一个「任务导向组织」,那么他很可能在专业技能上无法得到 Leader 的指导,格鲁夫希望通过让这个人在专业技能上报告给一个专业技能上的 Leader,使得这个人在专业技能上有所成长。 但是,格鲁夫也提到,这种双重报告很多时候是模糊不清的,「含混是解决问题之道」。所谓的含混,就是指专业技能的 Leader 在实际上并没有明确的权力。有些时候,双重报告的存在形式是一些「同级群体」或「同级委员会」,这些群体可能由于一些专业问题自发地形成,但是自主地决策解决一些 Leader 无法解决的问题。 我自己就亲自经过多次「同级群体」决策。例如,苹果规定 2016 年 6 月 1 日之后的应用必须支持 IPv6,这意味着我们可能需要升级全公司共用的网络库,于是我就在群里面发起了这个问题的讨论,一些人(主要是相关产品的 iOS 负责人)自发地参与了这个讨论,然后大家讨论出了一些方案和结论。 这种「同级群体」决策的成功,更大程度上不是某个规则的作用,因为我们很难明确出哪些事情需要跨部门讨论,也很难明确出这些讨论的负责人。所以,我们只能用一些企业文化或者做事方式影响大家。 所以,我感觉格鲁夫在本章其实并不是强调双重报告,而是强调在「任务导向组织」中,还应该有一只看不见的手,让大家在织织之间,产生协同、讨论和决策。 格鲁夫在本章中没有描述清楚这只看不见的手,他只把它称作「企业文化」,而这正是他在下一章将要展开阐述的内容。 第十章 每个人都听命于三个 “长官” 格鲁夫通过一个故事(故事中涉及买轮胎、遵守交通规则、主动帮助车祸的人)来说明一个人的行为,受三方面的影响: 自由市场因素:大家简单地以自己的利益作为行为指导,例如挑选商品时大多只会考虑价格和质量。 契约义务:通过事先达成的一致,然后履行契约义务。例如我们上班,就是和公司的一种契约义务。 文化价值观:一种为了组织利益,牺牲自我短期利益的行为,通常这种行为长远来看对个人也是有利的。 格鲁夫引入了 CUA 指标来帮助我们选择用以上哪方面的因素来指导人们的行为。CUA 分别指:工作环境的复杂性(Complexity)、不确定性(Uncertainty)、指令的模糊度(Ambiguity)。 程序员的工作就充满了复杂性,因为程序员需要不断地学习新知识,代码的逻辑和架构也可能很复杂。而市场的工作充满了不确定性,很多时候上司也无法帮你想出有新意的市场推广方案。 格鲁夫认为,如果一个工作的 CUA 因素高,而个人关注的是团体利益,那么就只能用文化价值观来作为行为的指导。但是如果个人关注的是自身利益,那么就会如下图显示的那样,情况变得「一筹莫展」。 格鲁夫举了一个例子,当海滩上发生灾难时,每个人都只顾及保全自己的性命,而救援工作需要极高的 CUA 因素,所以现场只会是一片混乱。 按这个理论思考,我们就能理解为什么要做火灾演习了,多次火灾演习可以极大地减少火灾发生的 CUA 因素,因为大家在演习中对于火灾已经有着明确的处理方案了,需要做的只是按之前演习中的契约行动就行了。 格鲁夫认为该理论对于指导新人也有意义: 让我们把这套理论套用在某个刚进公司的新人身上。由于初来乍到,他无疑比较关心自身的利益。因此,你应该给他明确的工作架构,降低复杂性及不确定性。 另外,该理论对于空降的高管也有意义: 对于空降的高管来说,就像起用任何新人一样,一开始他还是比较关心自身利益。但身为高级经理,他难免会被指派管理一个有问题的部门—毕竟这是我们从外面找人的原因。此时对这个经理人而言,他面临的不仅是烫手山芋,还有环境里很高的 CUA;同时,他也尚未建立起属于这个企业的价值观与行事准则。在此状况下,大家只能求老天保佑他能赶紧忘却私利,以大我为前提,并设法降低 CUA。如果他做不到这些,恐怕很快就会被撤掉。 文化价值观也不是银弹,在 CUA 因素低的时候,选择用自由市场因素或契约义务,都比文化价值观来得有效。所以,根据具体工作的 CUA 值,选择具体的控制模式,是经理人需要关注的。 不过话说回来,我仔细想了想互联网企业里面的各种职位,不管是产品、技术、还是运营,似乎都是高 CUA 因素的职位,所以文化价值观应该是互联网公司管理员工的基本方式。 很可惜,格鲁夫在本章中并没有详细介绍如何增强大家的文化价值观,他只是认为,管理者自己的行为示范,比把文化价值观挂在口头上有效。但是本书的第四部分,详细讨论了企业管理中人的问题。 第四部分:谋事在人 本部分涉及激励、工作成熟度、绩效评估、招人与留人、报酬与培训。 第十一章 激励部属参加比赛 格鲁夫将员工的问题分为不能和不为两类: 不能:能力不够。 不为:能力够,但是不够努力。 针对这两类问题,他提出了培训和激励两种解决方案。在本章作者并没有讲培训,主要详细讨论了激励相关的问题。 作者认为,激励应该和马斯洛的需求金字塔理论相符。 在「归属感与认同感」这一层,我们应该让同事们都喜欢当前的工作环境和同事关系,认同当前公司做的事情。同事之间的合作应该是愉快和融洽的,同事中还会有自己欣赏的牛人,有自己的好朋友可以一起吃饭、聊天。 只有产生了归属感与认同感,员工才会追求更高一层的「地位与尊重」。我们给那些表现优秀的员工更重要的事情,更高的职位,使得他能够在这一层上产生明确的目标。很多公司都会做职业发展的内部评级,其实就是给大家一个明确的地位与尊重的目标,让大家为此努力。 但是,「地位与尊重」的目标一旦达到,人们工作的动力又会下降。一些更牛的人,就会追求马斯洛需坟金字塔的顶端:「自我实现」。「自我实现」这一层的需求的差异性在于: 一旦某个人受激励的来源是自我实现,他工作的动力将不再受局限。这是自我实现有别于其他激励模式最重要的特点。其它的激励来源一旦在需求满足之后便不再生效,但是自我实现将不断激励个体向上突破。 有两种自我实现的动力可以促使个体将能力发挥到极致:精益求精型和成就导向型。 精益求精型的例子是音乐家、运动员,也包括程序员。拿程序员来说,一个程序员如果不断追求写出更牛逼的代码,那么他可以像阿里的多隆那样,成为合伙人级别的重要人物。 成就导向型的人常常怀有达成任务的决心,对于困难,他们喜欢挑战自我。其实做很多事情,刚开始都是需要面对失败的。成就导向型可以坦然地面对失败,然后再次挑战目标。 对于较高需求层次的人,失败的恐惧大多数是来自于内心而不是外界,如果不能克服自我内心的恐惧,那么这个人就会从自我实现的层次往下降。 一般而言,在较高的需求层次时,恐惧通常源自内在而非外在的威胁。人们经常因为过不了自己那一关而导致行动上的退却。但如果老是如此,这个人很快就会从自我实现的层次往下降落。 在具体实施激励时,格鲁夫认为,一个好的激励应该是目标明确的,并且这个目标应该是比较难以达到的,这样大家才会全力以付,发挥出尽量大的潜力。 如果我们想要让员工都能提升自我实现需求的层次,便必须先创造出一个讲求产出的环境。 另外,可以合理使用一些竞赛,让大家把竞技场上的争胜的心态应用到工作中。 工作的概念天生就不如竞技,我们干脆将运动场上的竞争精神融入工作。最好的方法便是先制定游戏规则,并让员工有衡量他们表现的尺度。 关于竞赛,我自己也有一些真实的感悟。我们公司很多人中午都会去游泳,之前大家都自己随便游,后来有一个同事说,我们分成两组,搞接力赛吧。虽然这是一个没有任何奖励的比赛,但是大家因为比赛,就会不自觉得更加努力游泳,连续多日下来,大家的体力都上升了很多。 关于激励,格鲁夫最后总结道: 经理人的角色在此便极为明显:他应当是个教练,身为教练,首先必须不居功,团队的成功来自于队员对教练指导的信赖;其次,他的训练必须严格。通过当一个铁面教头,他努力激发出队员的潜能,并刺激团队做出最佳表现。一个教练应该曾经是个好选手,因此他了解竞赛的规则以及选手在练习及比赛时可能面临的问题。 第十二章 工作成熟度 令人惊讶的是,即使较早建立起的管理理论多半靠直觉,后来的实证科学也并没有办法将它们推翻,或是证实某种管理风格确实较其他的更胜一筹。研究学者似乎必须下没有所谓最佳管理风格的定论。 格鲁夫首先通过英特尔在轮换经理人上的故事,引出了用「工作成熟度」(Task Relevant Maturity,TRM)来评估个人或部门。 根据工作成熟度的不同,格鲁夫建议用不同的办法来指导: 工作成熟度低时,指导应该是明确和具体的。包括做什么事情,何时完成,如何着手等。 工作成熟度中时,指导应该从具体的事情,转移到沟通、情绪上的支持与鼓励。 工作成熟度高时,指导只需要关注努力方向是否正确上。 格鲁夫说,我们在指导小孩的时候,也是符合这套理论的。刚孩子还小的时候,我们只会说做什么,不做什么;等他们长大一些之后,我们变成一些叮嘱和指导;等他们成人之后,我们基本上不再管教他们了。 指导的时候,我们应该注意建立共同的价值观。我们在猿题库也在这方面做了很多具体的尝试,比如我们强调:按时发布产品、代码质量、信息尽量共享、指导新人比日常开发工作更重要。这些都是在努力建立共同的价值观。 一旦员工了解了组织的营运价值观,又具有较高的工作成熟度时,主管便可以开始分权,进而提高自身的管理杠杆率。 格鲁夫在本章中也讨论了一个非常有意思的话题,管理者是否应该与员工建立友谊。他对此有两个观点: 我们不应该把友谊相关的社交活动与工作上的指导混为一谈。因为社交活动并不能直接在工作上产生帮助,当然,友谊对工作是有一些间接帮助的,因为它使得你们之间在沟通的时候会更加有效一些。 命令朋友其实是一件不愉快的事情。当你需要批评或直接命令朋友时,友谊可能会是一个阻碍。格鲁夫举了一个例子:当你需要给你的朋友打很低的绩效时,你是否感觉到非常难受? 对此我个人的感受是,适当的友谊还是非常有必要的,对于一些同事,经过一段时间的合作,我们其实是能够比较清楚地判断出来他们的潜力。如果我们认为他们的潜力是足够大的,在建立友谊的同时,在工作上也给予更多的指导,应该是一个更好的做法。 另外,建立共同的「就事论事」的价值观也是非常有必要的。大家是朋友,但是工作上应该批评就批评,如果大家有着对事不对人的共同价值观,批评就不是那么不可接受了。 第十三章 再难也得做:绩效评估 格鲁夫认为绩效评估是一个高杠杆率的工作,可以使得优秀的员工得到激励,从而更加努力。但是绩效评估又是一个非常难的事情,因为很容易产生冲突和争议。 绩效评估大致可以分成两部分:评估部属的绩效,以及将评估的结果告诉部属。作者认为,一个有效的评估报告应该包括:优点(需要有实例证明),缺点(需要有实例证明),如果在未来提高绩效。其实对于很多公司来说,绩效评估都是含混过去的。我现在所在的公司也没有详细到格鲁夫描述的那样的绩效评估报告。 不过,格鲁夫介绍了如何向一个完全不合格的员工传达绩效评估,我感觉很有价值。格鲁夫用解决问题的阶段来描述不合格员工的状态。 这些阶段具体解释如下: 忽视:表现不佳的员工最初会忽视问题。所以你需要找到具体的证据,让他无法抵赖。 否认:当员工开始否认问题时,事情其实已经有进展了,因为至少问题被提出来了。 责怪别人:责怪别人是一种很有效的防卫机制,因为员工可以以此为理由拒绝承担责任。所以这一步是关键,如果让他意识到不是别人的问题,那么就很容易进入到担起责任阶段。责怪别人到担起责任涉及的是克服心理障碍的问题,而从担起责任到寻找解决方案是能力问题,后者要简单得多。 担起责任:承认问题。 找出对策:双方一起找出问题的解决方案,并且实施。 格鲁夫把阶段分得很多,其实我倒觉得关键的阶段就是从否认责任到承担责任的过程,这个过程中,经理人需要收集到足够多的证据,尽量客观地沟通,另外强调就事论事的工作态度,才可能帮助员工克服心理障碍。 另外,即使到了最后的「找出对策」阶段,大家也可能无法达成一致,这个时候,格鲁夫建议不必在这阶段强求一致,只要员工承诺按经理的方案实施即可。我们不应该强求说服别人,因为这更多是一种心理上的需求。 你当然希望看到部属心悦诚服地同意你的看法,但如果他不是完全同意,只要他愿意采取改进行动,你就不该再在这上面伤脑筋。不要混淆了情绪问题和工作的需要。为了完成任务,你最需要的是部属愿意施行你决定的行动方案,至于他是否与你抱持同样的想法则是其次。期望别人凡事都和你想得一样其实并不是件好事,在工作上我们主要追求的是绩效,而并不是心里舒不舒服。 我们在做绩效评估时,也应该把重点放在那些重要的员工身上,他们已经非常优秀了,所以找出他们的问题将会相对困难,但是他们在未来很可能承担更重要的工作,所以把心思花在他们身上是值得的。 格鲁夫在本章的最后建议,应该提前把评估报告发给员工阅读,之后再组织讨论,这样会使得员工对评价有所思考,之后的讨论更加有效率。 第十四章 招人与留人 关于招人,格鲁夫提到,仅仅靠一小时的面试,根本就不足以客观地评价面试者的水平。对此我是非常同意的。但是企业的成本有限,确实也没办法花费更多时间来考查面试者了,所以这是一件非常难,但是又不得不做的事情。 关于如何招人,其实无非就是建立一套方法论,然后希望以「较大概率」招到满意的员工。我听过很多别的公司的方法论,大家的面试方法都差别很大,但是我觉得都是做到了刚刚说的原则。我自己长久以来针对程序员、产品经理、产品实习生面试分别都有总结,在此就不展开介绍书中的办法了。 关于留人,书中提到最麻烦的就是重要的优秀员工想离开。对待想离职的优秀员工,第一步需要做到的是足够的倾听。 你应该马上放下手上的事情,请他到办公室坐下来谈,问他为什么要辞职。让他畅所欲言,千万不要和他起任何争执。相信我,你的爱将已经在不止一个失眠的夜里将这套词儿演练过千百遍。等到他讲完所有他要辞职的理由(没有一个会是好理由),你再多问他一些问题。先让他说个够,因为当他讲完了事先准备好的那一套词儿后,真正的理由也许才会显现。千万不要争辩,不要说教,也不要动气。 倾听之后,找到离职真正的原因,只能站在对方立场上考虑,如果是薪水问题,看看是否合理,该调整的话就调整。如果是工作内容,看看能否做一些公司内部的工作变动来帮助他找到更喜欢的工作。如果是当前公司的一些具体的问题,看看能不能做一些改进。但是,这些做法的前提都是:这是一个优秀的、重要的员工。如果是一个表现普通的员工提出的不合理要求,那么倾听之后可能也只能做一些形式上的挽留了,因为我们不能破坏公司的薪酬体系来挽留他。 第十五章 报酬的诱惑 大部分人的薪资都是结合他的工作表现+工作年限的综合评价,这其实是建立员工稳定期望和公平的一个方案。在我们公司,有一些优秀的应届生能够比一些老员工贡献更多的产出,但是我们确实无法一下子就给他老员工那样的薪水,大部分的时候,我们会给他超出同样工作年限的人的薪水。 以工作年限作为薪资的重要衡量手段,算不上特别公平,但是确实也没有特别好的办法。不过,当前互联网公司已经有一些创业公司开始打破这样的规则,他们给那些工作一两年的优秀员工非常高的薪水,因为事实上,这些员工的产出和那些工作五六年的员工差别不大,但是从性价比上讲,他们比那些工作五六年的员工要价少得多,所以多给一些也没关系。 在互联网公司抢人的时候,这种策略被大量的采用了。这造成了互联网人才薪资水平的差异被进一步缩小,大部分人的年薪都集中在某一个很小的范围区间。而那些工作多年的人,如果不能进一步提升自己的能力,就会陷入薪资基本停止不前的怪圈。 在本章,作者也提到,一般职务的提升都会面临工作内容的巨大变化,很多人处理不好,反倒会表现得很差劲,这便是著名的“彼得原理”。 一名称职的教授被提升为大学校长后无法胜任;一个优秀的运动员被提升为主管体育的官员,导致无所作为。对一个组织而言,一旦相当部分人员被推到其不称职的级别,就会造成组织的人浮于事,效率低下,导致平庸者出人头地,发展停滞。 但是,对此我们又有什么办法呢?我们不提拔优秀的员工,难道提拔糟糕的员工吗?所以除了对提拔的员工悉心培养之外,也没什么好办法。 如果一个员工实在对新工作不感兴趣,作者建议还是让他回到以前表现优秀的岗位上。虽然刚开始有一些难堪,但总比他主动离职要好得多。 第十六章 别等火烧眉毛才培训 作者认为经理人应该是培训的责任人,不应该把培训交给外面的公司负责。因为经理人本身在公司内部具有权威性和可信度,他的培训内容更容易被理解,另外,每个公司的做事方式和文化都不太一样,自己参与培训才能够把正确的做事方式传递给大家。 设计培训课程花费的精力相当大,我当前就在设计产品实习生的培训课程,还好我之前有一些总结,否则第一次课可能都会耗费我大量时间。就算这样,我也不知道培训能否一直按计划进行下去。不管怎么样,只要开始了,总归是有产出的,而且我相信多做几次之后,我就可以建立起优秀的、系统的培训课程。 最后的问题列表 作者在最后留了一些很棒的问题,值得大家回答一翻。 如果你能从下列各项检验中拿到100分以上,以这本书的标准,你算是个杰出的经理人了。1、试着将你工作中的操作分为编制流程、组装及测试三个步骤。【10分】2、针对你手头开展的方案,找出限制步骤,并依此设计你的工作流程。【10分】3、找出你工作中最适合进行验货、线上检验与最终检验的地方。决定这些检验应该采用“海关”还是“监视器”的方式。然后考虑在什么时机下,你可以升格至“随机检验”。【10分】4、找出至少6项以上的新产出指标。这些指标应该要能衡量产出的质与量。【10分】5、将这些新的指标变成工作上的例行事项,并在部门会议中定期审视。【20分】6、你现在正寻找的最重要的战略(行动计划)是什么?描述你面临的环境需求以及计划进度。如果计划能成功地执行,是否能将你或你的公司带到理想中的境界?【20分】7、简化你最烦琐、最耗时的工作。至少让原有的步骤减少30%。【10分】8、找出什么是你真正的产出?你所管理的部门及影响力所及的部门的产出元素为何?按重要顺序排列。【10分】9、实际在公司中走动走动。然后,列出这次“出巡”中和你有关的事项。【10分】10、找一些借口让你一个月可以在公司内巡视一次。【10分】11、描述下一次你授权给部属时会如何督导。你将以什么为标准?怎么做?督导的频率是怎样的?【10分】12、列出你可以利用零碎时间进行的项目。【10分】13、列出和每一个部属“一对一会议”的时间表。(在会议之前向他们解释会议的目的,并要求他们作准备。)【20分】14、找出你上星期的日程表,将做的活动分为高、中、低杠杆率三类。设法多做一些高杠杆率的活动。(有哪些活动该减少或干脆不做?)【10分】15、预测下周有哪些事要瓜分你的时间。有多少时间要花在开会上?其中有多少是过程导向会议?多少是任务导向会议?如果后者占去的时间超过25%,你该如何设法删减?【10分】16、列出你的组织在未来三个月中最重要的三个目标,并一路验收成果。【20分】17、在与部属充分讨论过以上目标后,要他们也“依葫芦画瓢”—制定他们的目标并一路验收。【20分】18、写出“悬而未决”需作决策的事项。找出其中三项,试着运用决策制定过程的架构以及“六点问题”的方法。【10分】19、依据马斯洛的需求理论评估你自己的需求层次。并为部属找出他们所属的层次。【10分】20、给部属勾画他们的跑道,并找出每一个人的绩效指标。【20分】21、列出你给部属各种形式的工作所给予的相关回馈。他们是否能借着这些回馈来测量自己的进度?【10分】22、将你部属的工作成熟度分为低、中、高三类。并针对个人选出最适当的管理风格。并在你的管理风格及最适当的管理风格之间作比较。【10分】23、评估你上一次收到的或你对部属所作的绩效报告。这些报告对提高绩效有多大的影响?在上司告诉你报告内容或你告诉部属时,你们的沟通形式是怎样的?【20分】24、如果有哪一份报告不够理想,重做。【10分】 写在最后 我整理这份笔记花费了好几周,我从本书中收获巨大,希望你能从这篇总结中也有所收获,祝大家玩得开心~
目录: 一、什么是项目 二、项目的过程 三、项目思维 边界思维 过程思维 风险思维 干系人思维 整合沟通 复盘思维 一、什么是项目 项目是为了创造独特的产品,服务和成果而进行的临时性工作。项目具有如下特性: 二、项目的过程: 项目管理过程中有5大过程组:启动、规划、执行、监控、收尾。我们可以在不同的阶段(如产品需求、开发、测试等)循环使用这个过程组。 三、项目思维: 项目过程中主要包含5大思维:边界思维、过程思维、风险思维、干系人思维以及复盘思维,如下图: 3.1 边界思维: 边界思维包括正式立项,确定项目范围,做且只做成功完成项目所需的全部工作,合理管控变更并获得验收。 边界思维在项目过程中的运用如下: 3.2 过程思维: 过程思维包括分解工作,估算活动,制定计划和执行管控四个过程。 3.3 风险思维: 项目风险是指将来的事情,已经发生的消极风险常被称为问题。风险是每一个项目经理都了解的最大敌人,但也是最被忽视的管理内容,因为最大的风险是没有风险意识。 为些,我们需要提高项目中积极事件的概率和影响,降价项目中消极事件的概率和影响。 3.4 干系人思维: 干系人是积极参与项目或其利益可能受到项目实施或完成的积极或消极影响的个人、群体和组织。 a) 项目干系人通常包括如下: b)实施步骤: 3.5 整合沟通: a)沟通维度分析: b)沟通主要作用: 3.6 复盘思维: a)什么是复盘: 一个事情做完了,要有意识,然后把事情当初定的目标和现在的情况做对比,是不是按照预定情况出现的,哪些地方没有,为什么没有。 -----柳传志 b)为什么要复盘: 为了知其然知其所以然 为了同样的错误不要再犯 为了来传承经验,提升能力 为了总结规律,因化流程 把失败转化成财富 把成功转化成能力 c)如何复盘: d) 测评:
一、影响力的定义 首先,我们来看下牛津字典中对【影响力】的定义: "Use of Power to affect somebody's character,beliefs,or action through example,fear,admiration,etc." --运用力量以改变某个人的:个性、理念认知和行为行动 --这些力量包括:举例引证、造成恐惧、赞美肯定、权势财富等。 二、关于影响力的几个问题 了解了影响为的定义后,我们先思考以下几个问题,带着这几个问题继续学习本次课程: 1、影响他人过程中,遇到的最大障碍是什么? 2、这些障碍,哪些是外在的、哪些是自己本身的? 3、想要成功影响他人,一般透过什么方法或力量比较有效? 三、影响他人过程中常见的十个障碍 四、施展非职权影响的五个步骤 通常我们在施展非非职权影响力的过程中,有以下几个步骤,如图: 步骤一:理清自己的目标优序 进行影响之前,需先澄清: 我的主要目标、次要目标是什么? 我要影响对方的:个性、理念、行为? 这是个短期一次性的目标?还是必须长期奋斗的目标?这牵涉到我们要投入多少时间,运用何种筹码及策略。 我想达成的这些目标,是“必须( must)”要达成的?还是“有商量余地”的(nice-to-have)? 成功影响最有挑战的是:这些目标中,完成任务比较优先?还是维系双方的关系优先?还是两个都重要? 步骤二:分析各利益相关人的角色 如果我们面对的是一个组织,我们的第二个影响力挑战包括: 找出所有相关的利益人(stakeholders ): 组织内在大部分决策不会是由单一个人拍板,而是由几个具有相关专长或经验的人决定。 判断出这些人在组织中属于何种类型的角色: 每个人在组织中的地位会决定他将如何看待此事,一般而言有四种常见角色,如下图: 掌握有哪些看不见的组织力量会影响到这些人的决策判断?因为这些组织的客观外在因素通常会比这此人的个性及观点本身更具影响力! 步骤三:挖掘对方的利益与需求 PIN:除了掌握组织中相关的四种决策角色之外,我们还必须学会如何挖掘对方真正在意的事物: 沟通及决策风格:另外,还需掌握对方不同的沟通及决策风格,决定风格通常有以下几种: 对方可能会认为重要的需求因素例子: 步骤四:盘点自己手上的筹码 影响过程中,除了掌握对方的角色需求,跟管理自己的目标及情绪之外,自己拥有多少筹码足以让对方愿意配合你,也是秀关键的因素。 何谓筹码?人们想要的东西可以通称之为“筹码”:当我们拥有对方想要的东西(筹码)时,我们就有可能透过各种方式(例如交易)来影响对方,从而得到我们想要的事物。我们拥有的筹码越多,我们的影响力量就越大。 一般而言,多数人想要的东西都会超过一件以上!例如:声誉、金钱、信任、地位、安全、认识有份量人士、受到欢迎常识等等。这些跟之前提到的需求很相似。 一般而言,我们自己可以掌握的资源包括: 在困难时期的表现 在组织内的声誉 专长及经验 资历 个性性格 人际交往及沟通的能力 平时工作中表现出来来的意志力 在组织内外的社交关系网络 步骤五:灵活运用影响力策略 影响策略通过分为以下四大类,如下图: 策略一:类似与喜爱 Liking,又称为:信任式影响 这人策略的基础是:人们总是对喜欢的人说“yes” 熟悉:面孔,经常交流 相似:风格、穿着、背景、兴趣、个性、年纪 称赞:发自内心的夸奖 正面:积极、正面、情绪控制 形象:专业、整齐、洁净 策略二:互利互惠 Reciprocity,又称交易式影响 这个策略的基础是:在心里,人们总是希望从对方那边得到一些好处,相对的 ,人们也会愿意在适当时候作出相应的回报。 追溯交流记录 利用恩惠 Give-then-take(礼尚往来) Reject-then-Retreat(退而求其次) 策略三:承诺责任 Consistency,又称:承诺式的影响 这个策略的基础是:人们都希望自己能信守承诺,塑造自己在他人心中守信负责的形象,同时,也希望对方如此。 守信 负责 积极 主动 公开 策略四:社会认可 Social proof,又称为:社交式影响 这个策略的基础是:人们都有一种想要成为社会主流力量的潜在动机与愿望,同时也想一自己认同敬佩的有名专家或团体维持某种良好关系。 社交网络 同侪效应 社会声望 街头效应 关联效应 运用不同影响策略的例子: 五、总结:知己知彼,施展影响 大部分人都拥有比自己心里认知更多的筹码!掌握的筹码越多,自己的影响为就越大。而运用的影响策略越灵活多元,成功机率也就越大!
本篇文章主要简单总结下性能测试工具的原理以及如何选型。性能测试和功能测试不同,性能测试的执行是基本功能的重复和并发,需要模拟多用户,在性能测试执行时需要监控指标参数,同时性能测试的结果不是那么显而易见,需要对数据进行分析。这些特点决定了性能测试更适合通过工具来完成。 一、浅谈为什么需要工具 我们来看下工具的定义:它原指工作时所需用的器具,后引申为为达到、完成或促进某一事物的手段。(---来自百度的解释) 1、从人类进化的角度来看,会制造并使用工具是人和猿人最根本的区别,因为工具可以帮助我们提高生产力和效率。 2、想象下如果不使用工具进行性能测试会怎么样? 我们可以从性能测试的定义的角度来分析,性能测试是指通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。如果不使用工具,仅靠人工进行性能测试会存在以下的弊端: a)测试需要投入大量的资源: 为了模拟多种负载、并发的场景需要多人协同工作,通常测试没有很多的资源,而且就算有资源人工的效果也会大打折扣,甚至于某些场景仅凭人工是无法完成的。 b)可重复性非常差: 性能测试经常需要反复调优和测试执行,如果没有工具的帮助,全靠人工实在不敢想象。 c)测试准确性较差: 由于需要模拟多种负载和并发场景,如果由人工来操作,难免会存在误差,而且相对工具或程序来说这种误差会更大,对测试结果影响也非常大。 d)结果的收集、整理和呈现形式差: 如果没有工具,全凭人工采集数据相对工具来说也会存在较大的误差。 二、性能测试与性能测试工具的关系 1、性能测试从测试阶段来划分属于系统测试,其和具体使用什么工具并没有直接的关系。使用工具只是为了提高性能测试效率和准确性的一种方法和手段。从本质上来看,同做其它事情时使用工具没有什么实质性的区别。 2、性能测试不等于Loadrunner,LR只是性能测试工具其中的一种,而且它也不是万能的,在某些情况下它也并不能派上用场。推荐看下《让LoadRunner走下神坛》和《让LoadRunner再次走下神坛》这两篇文章于对性能测试和LR的关系讲的比较深刻。 3、自动化测试工具与性能测试工具的区别:性能测试工具一般是基于通信协议的(客户器与服务器交换信息所遵守的约定),它可以不关心系统的UI,而自动化使用的是对象识别技术,关注UI界面。自动化无法或很难造成负载,但是通过协议很容易。 三、性能测试工具选型参考: 通常在公司或项目中,我们选择任何工具时都会做一些调研,目的就是为了选择适合公司或项目的工具。那么性能测试工具也不例外,通常可以从以下几个方面进行考虑: 1、成本方面: a)工具成本:工具通常分为商业闭(shou)源(fei)和非商业开(mian)源(fei)两种,商业工具通常功能比较强大,收费,由于收费所以可提供售后服务,如果出了问题有专业人士帮忙处理。而开源工具通常是免费的,功能有限,维护工具的组织也是自发的,所以如果碰到问题需要自行解决,没有专人提供服务。具体选择商业还是开源的工具,需要根据公司的情况,比如公司规模、愿意承担的成本、项目综合情况等方面考虑。一般来看大公司通常可以承担的起工具的费用,会考虑购买商业工具。而小公司由于资金压力,可能会选择开源的工具。 b)学习成本:使用任何工具都需要进行学习,这样一来就会产生学习成本(比如:时间),因此我们在选择工具时也需要考虑到项目组成员的学习成本。如果有两种工具A和B都能满足项目组测试的需求,如果A工具大部分人都会使用,而B工具只有极少部分人会使用,那么建议优先考虑A工具。通常,对于测试人员最好熟悉一款流程的商业(性能)工具,一款开源免费(性能)工具,还需要熟悉常见的(性能)脚本开发语言等,这是基本要求。 2、支持的协议: 性能测试通常跟协议联系非常紧密,比如B/S的系统通常使用http协议进行客户端和服务器商的信息交换,C/S的系统通常使用socket协议进行信息交换。在选择工具时,需要考虑项目使用的协议。一个测试工具能否满足测试需求,能否达到令人满意的测试结果,是选择测试工具要考虑的最基本的问题。 3、生命力: 现在的性能测试工具非常多,比如LR,jmeter这类较大众的工具网上相关的资料非常多,但一些小众工具可能网上资料比较少。如果在工具使用过程中碰到了比较极手的问题,在录求解决方案或帮助时,大众的的工具相对来说会比较有优势一点,毕竟使用的人越多,资料越多,那么自己碰到的问题也许别人早就碰到并解决了,即时之前没有人碰到过,由于使用研究的人多,通过社区或论坛的帮助相信总会有高手能协助解决的。 4、跨平台: 这一点自不必多说,看看JAVA为什么一直这流行就知道了。 四、常见性能测试工具: 性能测试工具,从理论上来讲在性能测试过程中使用到的所有工具都可以称其为性能测试工具,通常分为以下几类: 说明: 服务器端性能测试工具:需要支持产生压力和负载,录制和生成脚本,设置和部署场景,产生并发用户和向系统施加持续的压力。 web前端性能测试工具:需要关于心浏览器等客户端工具对具体需要展现的页面的处理过程。 移动端性能测试工具:同web端性能测试工具也需要关心页面的处理过程,另外还要具体数据采集的功能,比如:手机CPU、内存、电量,启动时间等数据的记录。 资源监控工具:这个主要是能够收集性能测试过程中的数据以及良好的结果展现方式。 PS:本篇文章主要总结下服务器端性能测试工具LR和Jmeter,后面也会对这两个工具进行简单的对分。 五、常见性能测试工具特点 JMeter:采用的是多线程模型,扩展性很强,不过制造压力没有那么高。它很适合用来压一些Tomcat服务,或者一些后端接口。JMeter的缺点是压力值不能精确控制,难以适应高并发的情况,而且由于是JAVA编写的,本身比较消耗资源。 LoadRunner:更像是一个模拟器,它比较适用于前端构造较复杂场景的情况,比如模拟100个用户登录的场景,LoadRunner对非技术人员提供了很好的支持。LoadRunner不适用后端接口。 下表为JMeter和LoadRunner对比表: 描述 JMeter LoadRunner 架构原理 通过中间代理,监控和收集并发客户端的指令,把他们生成脚本,再发送的应用服务器,再监控应用服务器反馈的过程 同JMeter 安装 简单,解压即可,比较灵活 LoadRunner安装包比较大,安装比较麻烦,工具本身相对比较笨重 支持的协议 支持多种协议:HTTP、HTTPS、SOAP、FTP、Database via JDBC、JMS等,但相对LR还是不够全面,由于此原因相对来说jemter比较灵活,轻便 支持的协议非常多,比较全面,但正因此显得工具本身比较笨重,不够灵活 脚本录制 提供了一个利用本地ProxyServer(代理服务器)来录制生成测试脚本的功能,也支持badboy录制再生成JMeter脚本 自带录制功能强大,可直接录制回放 并发模型 通过增加线程组的数目,或者是设置循环次数来增加并发用户 支持多种并发模型,通过在场景中选择要设置什么样的场景,然后选择虚拟用户数 分布式测试 支持,可设置多台代理,通过远程控制实现多台机器并发压力 同JMeter 资源监控 通过JMeterPlugins插件和ServerAgent实现 自带资源监控功能 报告分析 通过与Ant集成,生成HTML报告 自身支持生成HTML、Word报告 虚拟IP 不支持 支持 网速模拟 不支持 支持 扩展性 开源,可根据需求修改源码 通过扩展函数库实现 学习成本 主要是自学官网上的资料 网上资料和相关培训很多,购买正版的话,还有技术支持 六、性能测试工具学习教程: 1、Loadrunner:目前还未整理,后续会慢慢整理成文章,敬请期待... 2、Jmeter:可查看我的另一篇文章Jmeter教程索引贴 3、Gatling:未使用过,网上资料也比较少,入门推荐:新一代服务器性能测试工具Gatling
本文主要介绍下性能测试的基本流程,性能测试从实际执行层面来看,测试的过程一般分为这么几个阶段,如下图: 下面分别介绍下每个阶段具体需要做什么: 一、性能需求分析: 性能需求分析是整个性能测试工作开展的基础,如果连性能的需求都没弄清楚,后面的性能测试执行其实是没有任何意义的,而且性能需求分析做的好不好直接影响到性能测试的结果。 一些性能测试人员常犯的错误就是测试一开始就直接用工具对系统进行加压,没有弄清楚性能测试的目的,稀里糊涂做完了以后也不知道结果是否满足性能需求。市面上的书籍也大都是直接讲性能测试工具如LR,jmeter如何使用,导致很多新手一提到性能测试就直接拿工具来进行录制回放,使得很多人认为会使用性能测试工具就等于会性能测试了,殊不知工具其实只是性能测试过程中很小的一部分。 在需求分析阶段,测试人员需要与项目相关的人员进行沟通,收集各种项目资料,对系统进行分析,建立性能测试数据模型,并将其转化为可衡量的具体性能指标,确认测试的目标。所以性能测试需求分析过程是繁杂的,需要测试人员有深厚的性能理论知识,除此之外还需要懂一些数学建模的知识来帮助我们建立性能测试模型。 首先,让我们来看看通过性能需求分析我们需要得出哪些结论或目标: 明确倒底要不要做性能测试?性能测试的目的是什么? 明确被测系统是什么?被测试系统的相关技术信息如:架构、平台、协议等 明确被测系统的基本业务、关键业务,用户行为 明确性能测试点是什么?哪些需要测,为什么?哪些不需要测,又是为什么? 明确被测系统未来的业务拓展规划以及性能需求? 明确性能测试策略,即应该怎么测试? 明确性能测试的指标,知道测试出来的结果怎么算通过? 其次,需求分析阶段我们可以从以下几个方面入手: 1、系统信息调研: 指对被测试系统进行分析,需要对其有全面的了解和认识,这是我们做好性能测试的前提,而且在后续进行性能分析和调优时将会大有用处,试想如果连系统的架构、协议都不了解,我们如何进行准确的性能测试?如果进行性能分析与调优? 需要分析的系统信息如下(包括但不仅限于如下这些): 2、业务信息调研: 指对被测试的业务进行分析,通过对业务的分析和了解,方便我们后续进行性能测试场景的确定以及性能测试指标的确定。 需要分析的业务信息如下(包括但不仅限于如下这些): 3、性能需求评估: 在实施性能测试之前,我们需要对被测系统做相应的评估,主要目的是明确是否需要做性能测试。如果确定需要做性能测试,需要进一步确立性能测试点和指标,明确该测什么、性能指标是多少,测试通过or不通过的标准?性能指标也会根据情况评估,要求被测系统能满足将来一定时间段的业务压力。 判断是否进行性能测试主要从下面两个方面进行思考: 业务角度: 系统是公司内部 or 对外?系统使用的人数的多少?如果一个系统上线后基本没几个人使用,无论系统多大,设计多么复杂,并发性的性能测试都是没必要的,前期可以否决。当然,除非在功能测试阶段发现非常明显的性能问题,使得用户体验较差的,此时可进行性能测试来排查问题。 系统角度:系统又可以从以下3个方面进行分析 a)系统架构: 如果一个系统采用的框架是老的系统框架(通常大公司都有自己的统一框架),只是在此框架上增加一些应用,其实是没有必要做性能测试,因为老框架的使用肯定是经过了验证的。如果一个系统采用的是一种新的框架,可以考虑做性能测试。 b)数据库要求: 很多情况下,性能测试是大数据量的并发访问、修改数据库,而瓶颈在于连接数据库池的数量,而非数据库本身的负载、吞吐能力。这时,可以结合DBA的建议,来决定是否来做性能测试。 c)系统特殊要求: 从实时性角度来分析,某些系统对响应时间要求比较,比如证券系统,系统的快慢直接影响客户的收益,这种情况就有作并发测试的必要,在大并发量的场景下,查看这个功能的响应时间。 从大数据量上传下载角度分析,某些系统经常需要进行较大数据量的上传和下载操作,虽然此种操作使用的人数不会太多,但是也有必要进行性能测试,确定系统能处理的最大容量,如果超过这个容量时系统需要进行相关控制,避免由于不人工误操作导致系统内存溢出或崩溃。 4、确定性能测试点: 在上面第3点中,我们简单分析了如何确定一个系统是否需要做性能测试。下面简单总结下如果一个系统确定要做性能测试,我们如何确定被测系统的性能测试点? 我们可以从下面几个方面进行分析: 关键业务: 确定被测项目是否属于关键业务,有哪些主要的业务逻辑点,特别是跟交易相关的功能点。例如转账,扣款等接口。如果项目(或功能点)不属于关键业务(或关键业务点),则可转入下面。 日请求量: 确定被测项目各功能点的日请求量(可以统计不同时间粒度下的请求量如:小时,日,周,月)。如果日请求量很高,系统压力很大,而且又是关键业务,该项目需要做性能测试,而且关键业务点,可以被确定为性能点。 逻辑复杂度: 判定被测项目各功能点的逻辑复杂度。如果一个主要业务的日请求量不高,但是逻辑很复杂,则也需要通过性能测试。原因是,在分布式方式的调用中,当某一个环节响应较慢,就会影响到其它环节,造成雪崩效应。 运营推广活动: 根据运营的推广计划来判定待测系统未来的压力。未雨绸缪、防患于未然、降低运营风险是性能测试的主要目标。被测系统的性能不仅能满足当前压力,更需要满足未来一定时间段内的压力。因此,事先了解运营推广计划,对性能点的制定有很大的作用。例如,运营计划做活动,要求系统每天能支撑多少 PV、多少 UV,或者一个季度后,需要能支撑多大的访问量等等数据。当新项目(或功能点)属于运营重点推广计划范畴之内,则该项目(或功能点)也需要做性能测试。 以上 4 点,是相辅相成、环环相扣的。在实际工作中应该具体问题具体分析。例如,当一个功能点不满足以上 4 点,但又属于资源高消耗(内存、CPU),也可列入性能测试点行列。 5、确定性能指标: 性能需求分析一个很重要的目标就是需要确定后期性能分析用的性能指标,性能指标有很多,可以根据具体项目选取和设定,而具体的指标值则需要根据业务特点进行设定,本文不详细进行阐述,后续可考虑就此单独写一篇。 二、性能测试准备 1、测试环境准备: a)系统运行环境:这个通常就是我们的测试环境,有些时候需求比较多,做性能测试担心把环境搞跨了影响其它的功能测试,可能需要重新搭建一套专门用来做性能测试的环境。 b)执行机环境:这个就是用来生成负载的执行机,通常需要在物理机上运行,而物理机又是稀缺资源,所以我们每次做性能测试都需要提前准备好执行机环境。 2、测试场景设计:根据性能需求分析来设计符合用户使用习惯的场景,场景设计的好不好直接影响到性能测试的效果。 3、性能工具准备: a)负载工具:根据需求分析和系统特点选择合适的负载工具,比如LR、Jmeter或galting等 b)监控工具:准备性能测试时的服务器资源、JVM、数据库监控工具,以便进行后续的性能测试分析与调优。 4、测试脚本准备:如果性能测试工具不能满足被测系统的要求或只能满足部分要求时,需要我们自己开发脚本配合工具进行性能测试。 5、测试数据准备: a)负载测试数据:并发测试时需要多少数据?比如登录场景? b)DB数据量大小:为了尽量符合生产场景,需要模拟线上大量数据情况,那么要往数据库里提前插入一定的数据量。这可能需要花费一些时间,特点是关联系统较多,逻辑复杂的业务可能同时涉及多张表。 6、其它:如果需要其它其它关联系统或专业人士如DBA配合的,也需要提前进行沟通。 三、性能测试执行 1、人工边执行边分析 通常我们做性能测试都是人工执行并随时观察系统运行的情况、资源的使用率等指标。性能测试的吸引力之一就在于它的不可预知性。当我们在做性能测试的时候遇到跟预期不符的情况很正常,这个时候需要冷静的分析。但这个过程可能会很慢长,需要不断的调整系统配置或程序代码来定位问题,耗时耗人力。特别是在当前敏捷开发模式比较流行的大环境下,版本发布非常频繁且版本周期短(通常1~2周一个版本),没有那么长的时间来做性能测试。 2、无人值守执行性能测试 无人值守是最理想化的目标,目前我们也朝着这个方向努力。无人值守不是说没有人力介入,而是把人为的分析和
随着软件行业的快速发展,现代的软件系统越来越复杂,功能越来越多,测试人员除了需要保证基本的功能测试质量,性能也随越来越受到人们的关注。但是一提到性能测试,很多人就直接连想到Loadrunner。认为LR就等于性能测试,其实这是不对的。LR只是性能测试的一个工具,但性能测试不仅仅是LR。本文会从以下几个方面介绍基础的性能测试理论,后续也会持续更新相关文章,尽量理论结合实践,让性能测试学习不在是工具的学习。 目录: 一、 什么是软件性能 二、不同群体眼中的性能 三、性能测试类型 四、性能测试应用场景 五、性能测试基本概念 六、理发店模型和地铁进站模型
地铁模型分析 和绝大部分人一样,小白每天都要乘坐地铁上下班,那么就拿地铁来分析,再次深刻理解下性能。早上乘坐地铁上班,最典型的就是北京地铁1、5、10、13号线等,人多得简直没法形容!为了方便理解分析,先做如下假设。 某地铁站进站只有3个刷卡机。 人少的情况下,每位乘客很快就可以刷卡进站,假设进站需要1s。 乘客耐心有限,如果等待超过30min,就会暴躁、唠叨,甚至选择放弃。 按照上述的假设,最初会出现如下的场景。 场景一:只有1名乘客进站时,这名乘客可以在1s的时间内完成进站,且只利用了一台刷卡机,剩余2台等待着。 场景二:只有2名乘客进站时,2名乘客仍都可以在1s的时间内完成进站,且利用了2台刷卡机,剩余1台等待着。 场景三:只有3名乘客进站时,3名乘客还能在1s的时间内完成进站,且利用了3台刷卡机,资源得到充分利用。 想到这里,小白越来越觉得有意思了,原来技术与生活这么息息相关,真的可以快乐学习哦。随着上班高峰的到来,乘客也越来越多,新的场景也慢慢出现了。 场景四:A、B、C三名乘客进站,同时D、E、F乘客也要进站,因为A、B、C先到,所以D、E、F乘客需要排队,等A、B、C三名乘客进站完成后才行。那么,A、B、C乘客进站时间为1s,而D、E、F乘客必须等待1s,所以他们3位在进站的时间是2s。 通过上面这个场景可以发现,每秒能使3名乘客进站,第1s是A、B、C,第2s是D、E、F,但是对于乘客D、E、F来说,“响应时间”延长了。 场景五:假设这次进站一次来了9名乘客,根据上面的场景,不难推断出,这9名乘客中有3名的“响应时间”为1s,有3名的“响应时间”为2s(等待1s+进站1s),还有3名的“响应时间”为3s(等待2s+进站1s)。 场景六:假设这次进站一次来了10名乘客,根据上面的推算,必然存在1名乘客的“响应时间”为4s,如果随着大量的人流涌入进站,可想而知就会达到乘客的忍耐极限。 场景七:如果地铁正好在火车站,例如,著名的北京西站、北京站。每名乘客都拿着大小不同的包,有的乘客拿的包太大导致卡在刷卡机那(堵塞),这样每名乘客的进站时间就会又不一样。 小白突然想到,貌似很多地铁进站的刷卡机有加宽的和正常宽度的两种类型,那么拿大包的乘客可以通过加宽的刷卡机快速进站(增加带宽),这样就能避免场景七中的现象。 场景八:进站的乘客越来越多,3台刷卡机已经无法满足需求,于是为了减少人流的积压,需要再多开几个刷卡机,增加进站的人流与速度(提升TPS、增大连接数)。 场景九:终于到了上班高峰时间了,乘客数量上升太快,现有的进站措施已经无法满足,越来越多的人开始抱怨、拥挤,情况越来越糟。单单增加刷卡机已经不行了,此时的乘客就相当于“请求”,乘客不是在地铁进站排队,就是在站台排队等车,已经造成严重的“堵塞”,那么增加发车频率(加快应用、数据库的处理速度)、增加车厢数量(增加内存、增大吞吐量)、增加线路(增加服务的线程)、限流、分流等多种措施便应需而生。 分析到这里,小白可以熟练地把性能指标与场景结合运用起来了,初步学习成果还是不错的。 原文:http://book.51cto.com/art/201502/465238.htm
本文主要分为两个部分: 第一部分:主要从问题出发,引入接口测试的相关内容并与前端测试进行简单对比,总结两者之前的区别与联系。但该部分只交代了怎么做和如何做?并没有解释为什么要做? 第二部分:主要介绍为什么要做接口测试,并简单总结接口持续集成和接口质量评估相关内容。 第一部分: 首先,在做接口测试的过程中,经常有后端开发会问: 后端接口都测试什么?怎么测的? 后端接口测试一遍 ,前端也测试一遍,是不是重复测试了? 于是,为了向开发解释上述问题,普及基本的测试常识,特意梳理了接口测试的相关内容以及其与前端测试的区别,使开发团队与测试团队在测试这件上达成基本的共识,提高团队协作效率,从而更好的保证产品质量。 然后,我们试着回答上面的问题: 问题1.1、后端接口都测试什么? --回答这个问题,我们可以从接口测试活动内容的角度下手,看一下面这张图,基本反应了当前我们项目后端接口测试的主要内容: 问题1.2、我们怎么做接口测试? --由于我们项目前后端调用主要是基于http协议的接口,所以测试接口时主要是通过工具或代码模拟http请求的发送与接收。工具有很多如:postman、jmeter、soupUI、java+httpclient、robotframework+httplibrary等。 问题2、后端接口测试一遍 ,前端也测试一遍,是不是重复测试了? --回答这个问题,我们可以直接对比接口测试和app端测试活动的内容,如下图为app测试时需要覆盖或考虑内容: 从上面这两张图对比可以看出,两个测试活动中相同的部分有功能测试、边界分析测试和性能测试,其它部分由于各自特性或关注点不同需要进行特殊的测试,在此不做讨论。接下来我们针对以上三部分相同的内容再进行分析: 1、基本功能测试: 由于是针对基本业务功能进行测试,所以这部分是两种测试重合度最高的一块,开发同学通常所指的也主要是这部分的内容。 2、边界分析测试: 在基本功能测试的基础上考虑输入输出的边界条件,这部分内容也会有重复的部分(比如业务规则的边界)。但是,前端的输入输出很多时候都是提供固守的值让用户选择(如下拉框),在这种情况下测试的边界范围就非常有限,但接口测试就不存在这方面的限制,相对来说接口可以覆盖的范围更广,同样的,接口出现问题的概率也更高。 3、性能测试: 这个比较容易区分,虽然都需要做性能测试,但关注点确大不相同。App端性能主要关注与手机相关的特性,如手机cpu、内存、流量、fps等。而接口性能主要关注接口响应时间、并发、服务端资源的使用情况等。两种测试时的策略和方法都有很大区别,所以这部分内容是需要分开单独进行测试的,理论上来说这也是不同的部分。 综论: 1、接口测试和app测试的活动有部分重复的内容,主要集中在业务功能测试方面。除此之外,针对各自特性的测试都不一样,需要分别进行有针对性的测试,才能确保整个产品的质量。 2、接口测试可以关注于服务器逻辑验证,而UI测试可以关注于页面展示逻辑及界面前端与服务器集成验证 第二部分: 1、什么是接口测试? 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换,传递和控制管理过程,以及系统间的相互逻辑依赖关系等。 2、为什么要做接口测试? a) 如今的系统复杂度不断上升,传统的测试方法成本急剧增加且测试效率大幅下降,接口测试可以提供这种情况下的解决方案。 b) 接口测试相对容易实现自动化持续集成,且相对UI自动化也比较稳定,可以减少人工回归测试人力成本与时间,缩短测试周期,支持后端快速发版需求。接口持续集成是为什么能低成本高收益的根源。 c) 现在很多系统前后端架构是分离的,从安全层面来说: 1、只依赖前端进行限制已经完全不能满足系统的安全要求(绕过前面实在太容易), 需要后端同样进行控制,在这种情况下就需要从接口层面进行验证。 2、前后端传输、日志打印等信息是否加密传输也是需要验证的,特别是涉及到用户的隐私信息,如身份证,银行卡等。 3、接口测试持续集成: 对接口测试而言,持续集成自动化是核心内容,通过持自动化的手段我们才能做到低成本高收益。目前我们已经实现了接口自动化,主要应用于回归阶段,后续还需要加强自动化的程度,包括但不限于下面的内容: a) 流程方面:在回归阶段加强接口异常场景的覆盖度,并逐步向系统测试,冒烟测试阶段延伸,最终达到全流程自动化。 b) 结果展示:更加丰富的结果展示、趋势分析,质量统计和分析等 c) 问题定位:报错信息、日志更精准,方便问题复现与定位。 d) 结果校验:加强自动化校验能力,如数据库信息校验。 e) 代码覆盖率:不断尝试由目前的黑盒向白盒下探,提高代码覆盖率。 f) 性能需求:完善性能测试体系,通过自动化的手段监控接口性能指标是否正常。 4、接口测试质量评估标准: a) 业务功能覆盖是否完整 b) 业务规则覆盖是否完整 c) 参数验证是否达到要求(边界、业务规则) d) 接口异常场景覆盖是否完整 e) 接口覆盖率是否达到要求 f) 代码覆盖率是否达到要求 g) 性能指标是否满足要求 h) 安全指标是否满足要求
新的一年即将到来,不知不觉2015年自己在Jmeter方面总结的文章有十几篇,在此汇总一下,顺便也算是个总结吧。2016年,继续学习技术,总结,写文章。 一、基础部分: 使用Jmeter进行http接口测试 Jmeter之Http Cookie Manager Jmeter之HTTP Request Defaults Jmeter之逻辑控制器(Logic Controller) Jmeter属性和变量 Jmeter组件执行顺序与作用域 Jmeter参数化 Jmeter关联 Jmeter分布式测试 Jmeter代理录制脚本 Jmeter调试工具---Debug Sampler Jmeter调试工具---HTTP Mirror Server 二、扩展部分: Jmeter之JDBC Request使用方法(oracle) Jmeter之Bean shell使用(一) Jmeter之Bean shell使用(二) 三、持续集成: ANT批量执行Jmeter脚本 搭建持续集成接口测试平台(Jenkins+Ant+Jmeter) Jmeter默认报告优化 Jmeter报告优化之New XSL stylesheet 四、其他: 1、基于InfluxDB&Grafana的JMeter实时性能测试数据的监控和展示 2、JMeter源码集成到Eclipse
Log4J的配置文件(Configuration File)就是用来设置记录器的级别、存放器和布局的,它可接key=value格式的设置或xml格式的设置信息。通过配置,可以创建出Log4J的运行环境。1. 配置文件Log4J配置文件的基本格式如下: #配置根Logger log4j.rootLogger = [ level ] , appenderName1 , appenderName2 , … #配置日志信息输出目的地Appender log4j.appender.appenderName = fully.qualified.name.of.appender.class log4j.appender.appenderName.option1 = value1 … log4j.appender.appenderName.optionN = valueN #配置日志信息的格式(布局) log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class log4j.appender.appenderName.layout.option1 = value1 … log4j.appender.appenderName.layout.optionN = valueN 其中 [level] 是日志输出级别,共有5级: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 Appender 为日志输出目的地,Log4j提供的appender有以下几种: org.apache.log4j.ConsoleAppender(控制台), org.apache.log4j.FileAppender(文件), org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件), org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件), org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方) Layout:日志输出格式,Log4j提供的layout有以下几种: org.apache.log4j.HTMLLayout(以HTML表格形式布局), org.apache.log4j.PatternLayout(可以灵活地指定布局模式), org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串), org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息) 打印参数: Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,如下: %m 输出代码中指定的消息 %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL %r 输出自应用启动到输出该log信息耗费的毫秒数 %c 输出所属的类目,通常就是所在类的全名 %t 输出产生该日志事件的线程名 %n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n” %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss ,SSS},输出类似:2002年10月18日 22 : 10 : 28 , 921 %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java: 10) 2. 在代码中初始化Logger: 1)在程序中调用BasicConfigurator.configure()方法:给根记录器增加一个ConsoleAppender,输出格式通过PatternLayout设为"%-4r [%t] %-5p %c %x - %m%n",还有根记录器的默认级别是Level.DEBUG. 2)配置放在文件里,通过命令行参数传递文件名字,通过PropertyConfigurator.configure(args[x])解析并配置;3)配置放在文件里,通过环境变量传递文件名等信息,利用log4j默认的初始化过程解析并配置;4)配置放在文件里,通过应用服务器配置传递文件名等信息,利用一个特殊的servlet来完成配置。3. 为不同的 Appender 设置日志输出级别:当调试系统时,我们往往注意的只是异常级别的日志输出,但是通常所有级别的输出都是放在一个文件里的,如果日志输出的级别是BUG!?那就慢慢去找吧。这时我们也许会想要是能把异常信息单独输出到一个文件里该多好啊。当然可以,Log4j已经提供了这样的功能,我们只需要在配置中修改Appender的Threshold 就能实现,比如下面的例子:[配置文件] ### set log levels ### log4j.rootLogger = debug , stdout , D , E ### 输出到控制台 ### log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = %d{ABSOLUTE} %5p %c{ 1 }:%L - %m%n ### 输出到日志文件 ### log4j.appender.D = org.apache.log4j.DailyRollingFileAppender log4j.appender.D.File = logs/log.log log4j.appender.D.Append = true log4j.appender.D.Threshold = DEBUG ## 输出DEBUG级别以上的日志 log4j.appender.D.layout = org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n ### 保存异常信息到单独文件 ### log4j.appender.E = org.apache.log4j.DailyRollingFileAppender log4j.appender.E.File = logs/error.log ## 异常日志文件名 log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR ## 只输出ERROR级别以上的日志!!! log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n [代码中使用] public class TestLog4j { public static void main(String[] args) { PropertyConfigurator.configure( " D:/Code/conf/log4j.properties " ); Logger logger = Logger.getLogger(this.getClass()); logger.debug( " debug " ); logger.error( " error " ); } } 运行一下,看看异常信息是不是保存在了一个单独的文件error.log中。 原文:http://www.blogjava.net/zJun/archive/2006/06/28/55511.html
网上看到的张图:
Jmeter默认的报告展示的信息比较少,如果出错了,不是很方便定位问题。由Jmeter默认报告优化这篇文章可知,其实由.jtl格式转换为.html格式的报告过程中,style文件起了很关键的作用。下面介绍另一种style文件的使用方法: 1、下载style文件:jmeter.results.shanhe.me.xsl 2、把下载的文件放到jmeter的extras目录下。 3、修改jmeter.properties文件如下部分,我这里都修改成true,这样执行完脚本后就会保存这些结果到.jtl文件里面: jmeter.save.saveservice.data_type=true jmeter.save.saveservice.label=true jmeter.save.saveservice.response_code=true # response_data is not currently supported for CSV output jmeter.save.saveservice.response_data=true # Save ResponseData for failed samples jmeter.save.saveservice.response_data.on_error=false jmeter.save.saveservice.response_message=true jmeter.save.saveservice.successful=true jmeter.save.saveservice.thread_name=true jmeter.save.saveservice.time=true jmeter.save.saveservice.subresults=true jmeter.save.saveservice.assertions=true jmeter.save.saveservice.latency=true jmeter.save.saveservice.connect_time=true jmeter.save.saveservice.samplerData=true jmeter.save.saveservice.responseHeaders=true jmeter.save.saveservice.requestHeaders=true jmeter.save.saveservice.encoding=false jmeter.save.saveservice.bytes=true jmeter.save.saveservice.url=true jmeter.save.saveservice.filename=true jmeter.save.saveservice.hostname=true jmeter.save.saveservice.thread_counts=true jmeter.save.saveservice.sample_count=true jmeter.save.saveservice.idle_time=true 4、修改build.xml文件,如下第7行style的值修改为新下载的xsl文件名: 1 <target name="report" depends="_message_xalan"> 2 <xslt 3 classpathref="xslt.classpath" 4 force="true" 5 in="${testpath}/${test}.jtl" 6 out="${testpath}/${test}.html" 7 style="${basedir}/jmeter-results-shanhe-me.xsl"> 8 <param name="showData" expression="${show-data}"/> 9 </xslt> 10 </target> 5、执行脚本,生成报告如下,明显感觉展示的内容比之前的报告多很多,定位问题也比较方便直观: 参考: https://testerhome.com/topics/3773 http://shanhe.me/node/18/314
一、本文目的: 之前写了两篇文章搭建持续集成接口测试平台(Jenkins+Ant+Jmeter)和ANT批量执行Jmeter脚本,功能实现上都没有什么问题,但是最后生成的报告有一点小问题,虽然不影响使用,但总是感觉不够完美,具体问题如下: 1、Date report这里的时间没有正确显示出来 2、Summary里的字段Min Time和Max Time显示的是NaN,没有显示正确的时间。 本文主要解决上述两个问题,具体报告如何生成可参考上面提到的两篇文章。 二、Jmeter+Ant报告生成原理: 在解决问题之前,让我们先弄清楚Jmeter+Ant是生成报告的原理,知道原理后我们就可以很从容的解决问题了。另外,如果后续我们想定制报告也就很容易了。 1、在Jmeter的extras目录下,官方已经为我们提供了一个现成的实例,我们只需要在该目录下执行ant命令就可以生成一个数据文件Test.jtl和一个报告Test.html(PS:如果没有安装ant需要先去安装,不会用ant的自行百度)。 2、知道了上一步后,接下来我们研究的重点就是extras目录下的build.xml文件了,具体研究细节就不在此细说了,因为这就部分内容属于ant的范围,有需要的可以自行补充下ant的知识。 三、解决问题: 1、找到extras目录下build.xml文件内容的如下部分:它的作用就是把生成的.jtl数据文件转换为.html格式的报告 具体属性的含义: in:生成的.jtl文件的路径 out:生成的.html文件的路径 style:从.jtl转换成.html所使用的样式,这些文件也在extras目录下,这个是最重要的部分,如果我们想定制报告可以自行定义这个文件或者从网上找一些合适的文件。 param:参数,这几个参数可以在style中使用,下面会讲到。 path:添加jar包的路径,在下面的target中有引用到(下面第9行)。 1 <path id="xslt.classpath">//jar的路径 2 <fileset dir="${lib.dir}" includes="xalan*.jar"/> 3 <fileset dir="${lib.dir}" includes="serializer*.jar"/> 4 </path> 5 //把生成的.jtl数据文件转换成.html格式的报告 6 <target name="xslt-report" depends="_message_xalan"> 7 <tstamp><format property="report.datestamp" pattern="yyyy/MM/dd HH:mm"/></tstamp> 8 <xslt 9 classpathref="xslt.classpath" 10 force="true" 11 in="${testpath}/${test}.jtl" 12 out="${testpath}/${test}.html" 13 style="${basedir}/jmeter-results-detail-report${style_version}.xsl"> 14 <param name="showData" expression="${show-data}"/> 15 <param name="titleReport" expression="${report.title}"/> 16 <param name="dateReport" expression="${report.datestamp}"/> 17 </xslt> 18 </target> 2、通过上面的分析,style 文件是整成报告转换的关键,那我们就打开jmeter-results-detail-report_21.xsl这个文件看看,找到如下几行,这里也定义了三个参数跟build.xml文件中一样,由此可猜测,我们只要在build.xml文件中定义dateReport这个参数和值,在style中就可以按如下方式使用,经过测试证明猜测是正确的,那么第一个问题就解决了: 1 <xsl:param name="showData" select="'n'"/> 2 <xsl:param name="titleReport" select="'Load Test Results'"/> 3 <xsl:param name="dateReport" select="'date not defined'"/> 3、对于第二个问题,其实把第1步中的代码复制到我们自己的build.xml文件中后,可以一并解决这两个问题。解决第二个总是的关键代码是第9行和第10行: classpathref="xslt.classpath" force="true" 而第9行又引用了第1~4行 4、到此,两个问题都解决了,最终修改后的build.xml文件如下,标黄是解决总是添加的代码: <?xml version="1.0" encoding="UTF-8"?> <project name="ant-jmeter-test" default="run" basedir="."> <!-- 需要改成自己本地的 Jmeter 目录--> <property name="jmeter.home" value="/Users/Tools/Jmeter" /> <property name="report.title" value="接口测试"/> <!-- jmeter生成jtl格式的结果报告的路径--> <property name="jmeter.result.jtl.dir" value="/Users/Desktop/jmx/report" /> <!-- jmeter生成html格式的结果报告的路径--> <property name="jmeter.result.html.dir" value="/Users/Desktop/jmx/report" /> <!-- 生成的报告的前缀--> <property name="ReportName" value="TestReport" /> <property name="jmeter.result.jtlName" value="${jmeter.result.jtl.dir}/${ReportName}.jtl" /> <property name="jmeter.result.htmlName" value="${jmeter.result.html.dir}/${ReportName}.html" /> <target name="run"> <antcall target="test" /> <antcall target="report" /> </target> <target name="test"> <taskdef name="jmeter" classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask" /> <jmeter jmeterhome="${jmeter.home}" resultlog="${jmeter.result.jtlName}"> <!-- 声明要运行的脚本"*.jmx"指包含此目录下的所有jmeter脚本--> <testplans dir="/Users/Desktop/jmx" includes="*.jmx" /> <property name="jmeter.save.saveservice.output_format" value="xml"/> </jmeter> </target> <path id="xslt.classpath"> <fileset dir="${jmeter.home}/lib" includes="xalan*.jar"/> <fileset dir="${jmeter.home}/lib" includes="serializer*.jar"/> </path> <target name="report"> <tstamp> <format property="report.datestamp" pattern="yyyy/MM/dd HH:mm" /></tstamp> <xslt classpathref="xslt.classpath" force="true" in="${jmeter.result.jtlName}" out="${jmeter.result.htmlName}" style="${jmeter.home}/extras/jmeter-results-detail-report_21.xsl"> <param name="dateReport" expression="${report.datestamp}"/> </xslt> <!-- 因为上面生成报告的时候,不会将相关的图片也一起拷贝至目标目录,所以,需要手动拷贝 --> <copy todir="${jmeter.result.html.dir}"> <fileset dir="${jmeter.home}/extras"> <include name="collapse.png" /> <include name="expand.png" /> </fileset> </copy> </target> </project> 5、修改后的报告:
上一篇Jmeter之Bean shell使用(一)简单介绍了下Jmeter中的Bean shell,本文是对上文的一个补充,主要总结下常用的几种场景和方法,相信这些基本可以涵盖大部分的需求。本节内容如下: 一、操作变量 二、操作属性 三、自定义函数 四、引用外部java文件 五、引用外部class文件 六、引用外部Jar包 七、其它用法(接受参数, log等) 一、操作变量:通过使用Bean shell内置对象vars可以对变量进行存取操作 a) vars.get("name"):从jmeter中获得变量值 b) vars.put("key","value"):数据存到jmeter变量中 二、操作属性:通过使用Bean shell内置对象props 可以对属性进行存取操作 a) props.get("START.HMS"); 注:START.HMS为属性名,在文件jmeter.properties中定义 b) props.put("PROP1","1234"); 三、自定义函数: 在BeanShell中,我们可以使用java语言自定义函数来处理特定的逻辑,结合BeanShell的内置对象进行变量的存取,方便我们进行测试提高脚本的灵活性。 示例: 1、在Test Plan中添加一个变量:hello = kitty 2、Debug sampler-1和Debug sampler-2什么都不处理,用来查询对比beahshell处理前后的结果 3、BeanShell Sampler中的脚本如下: 4、运行结果: Debug sampler-1中显示:hello=kitty BeanShell sampler中 返回结果为:success Debug sampler-1中显示:hello=world,jmeter=111111 四、引用外部java文件: 有没有觉得上面(三)中自定义函数这样的方式太麻烦并且也不美观?而且如果我们已经有现成的java源文件或者class文件时,我们有没有什么办法直接在jemter中引用?这就是这部分要介绍的内容,直接上示例: 1、假如我有一个java 源文件,名为:Myclass.java,代码如下: package test; public class Myclass { public int add(int a, int b) { return a + b; } } 2、Bean Shell使用代码如下: 在bean shel中通过source("代码路径")方法引入java,然后调用方法和java一样,new一个class,再调用里面的add 方法。 3、运行结果: 五、引用外部class文件: 现在知道如何引用外部文件,有时候如果我们只有class文件怎么办呢?其实在jmeter中也可以直接引用class文件,示例如下: 1、直接把上例中的java文件编译成class文件,如何编译请自行百度。 2、Bean Shell使用代码如下: 用addClassPath("D:\\")方法引入 class文件,在用import导入包及类,然后就可以像java一样调用了 3、运行结果: 六、引用外部Jar包: 上面四、五介绍了如何引用外部java和class文件,如果文件比较多时我们可以把它们打成一个jar包然后在jemter中调用,具体如何使用可以看我上一篇有介绍:Jmeter之Bean shell使用(一)。 在这里想补充一点的是jmeter中引入jar的方法: 1、上一篇中已使用过的:把jar包放到jmeter目录\apache-jmeter-2.13\lib\ext下 2、在Test Plan的右侧面板最下方直接添加需要引用的jar包,如下图: 七、其它用法: 1、在Test Plan中定义如下三个变量: 2、Bean Shell可脚本如下: a、bean shell可以接受传入参数,如下图:${u1} ${u2} ${u3} b、参数可以通过bsh.args[]按顺序提取 c、bean shell提供了一个内置变量Parameters,来保存参数的集合 3、运行结果: 下图中1输入的这两句设置: ResponseCode = 500;ResponseMessage = "This is a test"; 下图中2输入的这两句设置: log.info(Parameters); log.info(Label); 官网: http://jmeter.apache.org/usermanual/component_reference.html#BeanShell_Sampler
一、什么是Bean Shell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法; BeanShell是一种松散类型的脚本语言(这点和JS类似); BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简的解释器jar文件大小为175k。 BeanShell执行标准Java语句和表达式,另外包括一些脚本命令和语法。 官网:http://www.BeanShell.org/ 二、Jmeter有哪些Bean Shell 定时器: BeanShell Timer 前置处理器:BeanShell PreProcessor 采样器: BeanShell Sampler 后置处理器:BeanShell PostProcessor 断言: BeanShell断言 监听器: BeanShell Listener 三、BeanShell的用法 在此介绍下BeanShell PreProcessor的用法,其它的beahshell可以类推。在此我们使用beahshell调用自己写的工具类,工具类实现了密码的加、解密功能: 1、在eclipse写好代码,然后把该类打成jar包(在类上点击右键->Export->jar file) 2、把jar包放到jmeter目录\apache-jmeter-2.13\lib\ext下 3、打开jmeter,添加一个http sampler(调用登录接口),在sampler下添加一个BeanShell PreProcessor 4、在beanshell PreProcessor中导入我们的jar包,调用里面的加、解密码方法,把结果保存在jmeter变量中,下面两个方法是beanshell中我们最常用到的: vars.get(String paramStr):获得变量值 vars.put(String key,String value):,将数据存到jmeter变量中 import com.pingan.ff.account.user.utils.*; //加密 System.out.println("*****加密*****"); String password = "123123"; String encode = SecurityUtils.getKey(password);//调用工具类中的方法进行加密 System.out.println("Set my encode"); vars.put("encode",encode);//把值保存到jmeter变量encode中 String getEncode=vars.get("encode"); System.out.println("Get my encode: " + getEncode); 5、把加密后的密码存到jmeter变量中,然后在http sampler中就可以通过${encode}进行使用了: 6、执行脚本: 四、Bean Shell常用内置变量 JMeter在它的BeanShell中内置了变量,用户可以通过这些变量与JMeter进行交互,其中主要的变量及其使用方法如下: log:写入信息到jmeber.log文件,使用方法:log.info(“This is log info!”); ctx:该变量引用了当前线程的上下文,使用方法可参考:org.apache.jmeter.threads.JMeterContext。 vars - (JMeterVariables):操作jmeter变量,这个变量实际引用了JMeter线程中的局部变量容器(本质上是Map),它是测试用例与BeanShell交互的桥梁,常用方法: a) vars.get(String key):从jmeter中获得变量值 b) vars.put(String key,String value):数据存到jmeter变量中 更多方法可参考:org.apache.jmeter.threads.JMeterVariables props - (JMeterProperties - class java.util.Properties):操作jmeter属性,该变量引用了JMeter的配置信息,可以获取Jmeter的属性,它的使用方法与vars类似,但是只能put进去String类型的值,而不能是一个对象。对应于java.util.Properties。 a) props.get("START.HMS"); 注:START.HMS为属性名,在文件jmeter.properties中定义 b) props.put("PROP1","1234"); prev - (SampleResult):获取前面的sample返回的信息,常用方法: a) getResponseDataAsString():获取响应信息 b) getResponseCode() :获取响应code 更多方法可参考:org.apache.jmeter.samplers.SampleResult sampler - (Sampler):gives access to the current sampler 官网: http://jmeter.apache.org/usermanual/component_reference.html#BeanShell_Sampler http://jmeter.apache.org/usermanual/component_reference.html#BeanShell_PreProcessor
JDBC Request: 这个sampler可以向数据库发送一个jdbc请求(sql语句),它经常需要和JDBC Connection Configuration 配置元件一起配合使用。 目录: 一、准备工作 二、配置JDBC Connection Configuration 三、配置JDBC Request 四:JDBC Request参数化 五:Variables names参数使用方法 六:Result variable name参数使用方法 七:数据库驱动类和URL格式 一、准备工作: 1、本文使用oracle 数据库进行测试,数据库实例名为ORCL,用户名密码为scoff/****** 2、数据库中有表:DEPT,表中数据如下: 3、复制ORACLE的JDBC驱动JAR包文件(我的在:D:\oracle\product\10.2.0\db_1\jdbc\lib\ojdbc14.jar)到JMeter的lib目录下 或者 在Jmeter的Test Plan中引入ojdbc14.jar包 二、配置JDBC Connection Configuration: 重要参数说明: Variable Name:数据库连接池的名称,我们可以有多个jdbc connection configuration,每个可以起个不同的名称,在jdbc request中可以通过这个名称选择合适的连接池进行使用。 Database URL:数据库url,jdbc:oracle:thin:@host_ip or machine_name:Oracle 监听器监听的端口:Oracle实例的名 (可在oracel安装目录下tnsnames.ora文件中找到这些信息) JDBC Driver class:JDBC驱动 username:数据库登陆的用户名 passwrod:数据库登陆的密码 三、配置JDBC Request: 1、重要参数说明: Variable Name:数据库连接池的名字,需要与JDBC Connection Configuration的Variable Name Bound Pool名字保持一致 Query:填写的sql语句未尾不要加“;” Parameter valus:参数值 Parameter types:参数类型,可参考:Javadoc for java.sql.Types Variable names:保存sql语句返回结果的变量名 Result variable name:创建一个对象变量,保存所有返回的结果 Query timeout:查询超时时间 Handle result set:定义如何处理由callable statements语句返回的结果 2、执行结果: 四:JDBC Request参数化: 方法(一): 定义变量,在sql quety中使用变量: 1、在Test plan中定义三个变量(当然也可以使用参数化:Jmeter参数化): 2、在sql query中使用${变量名}的方式引用: 方法(二): 在sql quety中使用“?”作为占位符,并传递参数值和参数类型,如下图: 1、传递的参数值是常量,如下图传递了3个常量:10,ACCOUNTINGNEW YORK: 2、传递的参数值是变量,如下图中${DNAME}: 五:Variables names参数使用方法: Jmeter官网给的解释是:如果给这个参数设置了值,它会保存sql语句返回的数据和返回数据的总行数。假如,sql语句返回2行,3列,且variables names设置为A,,C,那么如下变量会被设置为: A_#=2 (总行数) A_1=第1列, 第1行 A_2=第1列, 第2行 C_#=2 (总行数) C_1=第3列, 第1行 C_2=第3列, 第2行 如果返回结果为0,那么A_#和C_#会被设置为0,其它变量不会设置值。 如果第一次返回6行数据,第二次只返回3行数据,那么第一次那多的3行数据变量会被清除。 可以使用${A_#}、${A_1}...来获取相应的值 示例: 我们还是用上面的数据库,把所有数据查出来,DEPT表有有3个字段,4条记录(忘记了的可以回到第一步那里查看) 1、添加一个jdbc request名为select4,添加一个Debug Sampler用来查看输出的结果,设置 variables name为a,b,c: 2、执行结果: 六:Result variable name参数使用方法: 如果给这个参数设置值,它会创建一个对象变量,保存所有返回的结果,获取具体值的方法:columnValue = vars.getObject("resultObject").get(0).get("Column Name") 执行结果: 七:数据库驱动类和URL格式: Datebase Driver class Database URL MySQL com.mysql.jdbc.Driver jdbc:mysql://host:port/{dbname} PostgreSQL org.postgresql.Driver jdbc:postgresql:{dbname} Oracle oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@//host:port/service OR jdbc:oracle:thin:@(description=(address=(host={mc-name}) (protocol=tcp)(port={port-no}))(connect_data=(sid={sid}))) Ingres (2006) ingres.jdbc.IngresDriver jdbc:ingres://host:port/db[;attr=value] MSSQL com.microsoft.sqlserver.jdbc.SQLServerDriver 或者 net.sourceforge.jtds.jdbc.Driver jdbc:sqlserver://IP:port;databaseName=DBname 或者 jdbc:jtds:sqlserver://localhost:1433/"+"library" 官网例子(mysql):http://jmeter.apache.org/usermanual/build-db-test-plan.html 关于jmeter中jdbc相关参数的应用: http://f.dataguru.cn/thread-554702-1-1.html
之前我介绍过Jmeter的一种调试工具Debug Sampler,它可以输出Jmeter的变量、属性甚至是系统属性而不用发送真实的请求到服务器。既然这样,那么HTTP Mirror Server又是做什么用的呢? 一、HTTP Mirror Server的作用: 它可以在本地临时搭建一个HTTP服务器,该服务器把接收到的请求原样返回,这样就可以看到发送出的请求的具体内容,以供调试。 二、示例: 1、添加HTTP Mirror Server: 右键点击WorkBench-->Add-->Non-Test Elements-->HTTP Mirror Server ,点击【Start】启动 2、发送请求到该服务器: 3、执行结果: request: Response: 可以看到:response中的内容与request内容一模一样,我们就可以通过此种方法判断我们发送出去的请求是否确实是我们预期的结果。 官网: http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Mirror_Server
一、Jenkins下载安装 1、到官网下载jenkins.war包:http://jenkins-ci.org/ 2、安装方法有两种: a) 把下载下来的jenkins.war包放到文件夹下,如C:\jenkins,然后打开命令行窗口并进到该目录下,执行java -jar jenkens.war命令,当提示:“Jenkins is fully up and running”时,表示启动成功,这时在浏览器窗口输入:http://localhost:8080/ 就可到jenkins的首页。 b) 如果有tomcat,把jenkins.war包放在tomcat的webapps文件夹下,启动tomcat时会自动启动jenkins,这时通过http://localhost:8080/jenkins就 可以访问jenkins的首页了。 3、我使用的是第一种方法,安装好后访问: http://localhost:8080 二、 Jenkins配置 1、修改jenkins的根目录: 默认地在C:\user\.jenkins ,可以通过设置环境变量来修改,例如:set JENKINS_HOME=D:\jenkins,然后重新启动jenkins。 2、备份和恢复jenkins: 只需要备份JENKINS_HOME下的所有文件和文件夹,恢复的时候需要先停止jenkins。 3、移动,删除或修改jobs: a) 移动或删除jobs:移动或删除%JENKINS_HOEM%\jobs目录。 b) 修改jobs的名字:修改%JENKINS_HOEM%\jobs下对应job的文件夹的名字。 c) 对于不经常使用的job,只需要对%JENKINS_HOEM%\jobs下对应的jobs的目录zip或tar后存储到其他的地方。 三、Jenkins架构(master-slave) 1、Master/Slave相当于Server和agent的概念,Master提供web接口让用户来管理job和slave,job可以运行在master本机或者被分配到slave上运行。一个master可以关联多个 slave用来为不同的job或相同的job的不同配置来服务。 2、在 Slave上执行JOB时,Slave需要安装可运行环境。 3、Slave可以是物理机也可以是虚拟机 四、管理节点(slave) 1、点击系统管理-->管理节点-->新建节点,输入节点的名字,选中【Dumb Slave】,点击 【OK】 2、slave配置: a) of executors:表示在slave上可以并行执行几个线程,也可以点后面的问号看说明,一般设置为1。 b) 远程工作目录:在slave上创建jenkins工作目录的路径,一般设置为D:\JK c) 标签:可以给slave加上一个或多个标签,通过标签选择slave d)启动方法:启动slave的方法,推荐选第二个Launch slave agents via Java Web Start 3、设置好后,点击保存,出现在下图界面: 4、上面看到有三种方法可以启动slave,我们就使用第二种,在本机cmd输入: javaws http://localhost:8080/computer/testa/slave-agent.jnlp 启动slave成功界面: 五、配置JOB 1、在jenkins首页点击【新建】任务的,选择【构建一个自由风格的软件项目】,输入名字后点击【OK】 2、进行JOB配置页面: a)Restrict where this project can be run: 创建slave时的标签就在这里用上了,用来指定这个Job在哪个标签的slave上执行b)源码管理:推荐使用SVN,也不可选None c)增加构建步骤: 1、Execute Windows batch commnd:这个就是windows命令行参数(默认当前路径是job的workspace,如果命令很多可以写成批处理文件放在job的工作目录下,在这引用就好) 2、Execute shell:运行shell、python,perl,ruby等脚本 3、Invoke Ant:支持Ant构建 4、Invoke top-level Maven targets:支持Maven构建 d)增加构建后操作步骤: 这里有比较比的选项,可以根据自己的需要选择,常用的是发送邮件,也可以安装jenkins的插件,安装插件后这里会有相应的选项。 e)配置完成job后就可以保存,执行job。 六、插件管理 1、点击系统管理-->管理插件,进入插件管理页面,可以选择需要的插件进行安装: 2、选择【高级】这里可以上传插件后缀为hpi的文件,等他提示安装完成,然后重启Jenkins就可以完成安装了,插件下载地址: http://mirrors.jenkins-ci.org/plugins/ 七、权限管理 未完待续... 参考: http://www.cnblogs.com/itech/archive/2011/11/23/2260009.html
Jmeter之逻辑控制器(Logic Controller) 前言: 1、 Jmeter官网对逻辑控制器的解释是:“Logic Controllers determine the order in which Samplers are processed.”。意思是说,逻辑控制器可以控制采样器(samplers)的执行顺序。由此可知,控制器需要和采样器一起使用,否则控制器就没有什么意义了。放在控制器下面的所有的采样器都会当做一个整体,执行时也会一起被执行。 2、JMeter中的Logic Controller分为两类: a) 控制测试计划执行过程中节点的逻辑执行顺序,如:Loop Controller、If Controller等; b) 对测试计划中的脚本进行分组、方便JMeter统计执行结果以及进行脚本的运行时控制等,如:Throughput Controller、Transaction Controller。 3、Jmeter提供如下这么多的控制器: 一、简单控制器(Simple Controller): 作用:这是Jmeter里最简单的一个控制器,它可以让我们组织我们的采样器和其它的逻辑控制器(分组功能),提供一个块的结构和控制,并不具有任何的逻辑控制或运行时的功能。 二、循环控制器(Loop Controller): 作用:指定其子节点运行的次数,可以使用具体的数值(如下图,设置为5次),也可以使用变量 1、Forever选项:勾选上这一项表示一直循环下去 2、如果同时设置了线程组的循环次数和循环控制器的循环次数,那循环控制器的子节点运行的次数为两个数值相乘的结果。 三、仅一次控制器(Once Only Controller): 作用:在测试计划执行期间,该控制器下的子结点对每个线程只执行一次,登录场景经常会使用到这个控制器。 注意:将Once Only Controller作为Loop Controller的子节点,Once Only Controller在每次循环的第一次迭代时均会被执行。 四、ForEach控制器(ForEach Controller): 作用:ForEach控制器一般和用户自定义变量一起使用,其在用户自定义变量中读取一系列相关的变量。该控制器下的采样器或控制器都会被执行一次或多次,每次读取不同的变量值。如下图: 参数: Input Variable Prefix:输入变量前缀 Output variable name:输出变量名称 Start index for loop(exclusive):循环开始的索引(这里如果不填写,默认从1开始,如果没有1开始的变量,执行时会报错) End index for loop(inclusive):循环结束的索引 Add”_”before number:输入变量名称中是否使用“_”进行间隔。 用户自定义变量: 变量名前缀为ForEach Controller中Input variable prefix定义的name + 下划线(上图中我们勾选了下划线)+数字编号 执行结果: 总共执行了3次,每次执行时会把获取到的变量值赋值给输出变量outNmae,其它地方可以通过${outNmae}进行调用。 五、事务控制器(Transaction Controller): 作用: 事务控制器会生产一个额外的采样器,用来统计该控制器子结点的所有时间。 参数: Generate parent sample:(选中这个参数结果展示如下图红框,否则显示为下图蓝框) Include duration of timer and pre-post processors in generated sample:选中这一项会统计定时器(timer)的时间,否则只统计采样器(sample)的时间 六、If 控制器(If Controller): 作用:根据给定表达式的值决定是否执行该节点下的子节点,默认使用javascript的语法进行判断(如下图红框内的文字)。 参数: Interpret Condition as Variable Expression?:选中这一项时表示:判断变量值是否等于字符串true(不区分大小写) Evaluate for all children:如果选中这一项,在每个子结点执行前都会计算表达式 示例一:使用变量的方式进行判断: 示例二:选中Interpret Condition as Variable Expression? 七、Switch控制器(Switch Controller): 作用:Switch控制器通过给该控制器中的Value赋值,来指定运行哪个采样器。有两种赋值方式: 第一种是数值,Switch控制器下的子节点从0开始计数,通过指定子节点所在的数值来确定执行哪个元素。 第二种是直接指定子元素的名称,比如采样器的Name来进行匹配。当指定的名称不存在时,不执行任何元素。 当Value为空时,默认执行第1个子节点元素。 示例: 1、Switch Controller选择的值为login page 2、执行结果: 八、吞吐量控制器(Throughput Controller): 作用:控制其下的子节点的执行次数与负载比例分配,也有两种方式: Total Executions:设置运行次数 Percent Executions:设置运行比例(1~100之间) 示例: 1、设置线程组循环5次: 2、Throughput Controller1的子结点执行3次: 3、Throughput Controller2的子结点执行(40% * 线程组循环次数5)= 2次: 执行结果: 九、随机控制器(Random Controller): 作用:随机执行其下的所某个子结点 十、随机顺序控制器(Random Order Controller): 作用:随机执行其下的所有子结点 官网地址: http://jmeter.apache.org/usermanual/component_reference.html#logic_controllers
一、Jmeter中的属性: 1、JMeter属性统一定义在jmeter.properties文件中,我们可以在该文件中添加自定义的属性 2、JMeter属性在测试脚本的任何地方都是可见的(全局),通常被用来定义一些JMeter使用的默认值,可以用于在线程间传递信息。 3、JMeter属性可以在测试计划中通过函数 _P 进行引用,但是不能作为特定线程的变量值。 4、JMeter属性可以通过_setProperty 函数来定义JMeter属性 5、JMeter属性是大小写敏感的 6、WorkBench中的属性查看组件: WorkBench右键--->Add--->Non Test Elements--->Property Display 二、Jmeter中的变量: 1、JMeter变量对于测试线程而言是局部变量。 2、在不同测试线程中,JMeter变量既可以是完全相同的,也可以是不同的。 3、JMeter变量引用方法:${name} 4、JMeter变量是大小写敏感的 5、如果有某个线程更新了变量,那么仅仅是更新了变量在该线程中复制的值 6、Jmeter中定义变量的地方: a) 测试计划(Test plan),在右边的面板上添加User Defined Variables b) 线程组,右键选择 配置元件( config element)-->User Defined Variables c) 通过前置或后置处理器生成的变量,可参考我的另一篇:Jmeter关联 d)使用csv参数化的变量,参数化可参考我另一篇:Jmeter参数化 注意:通过 a 和 b 两种方式定义的变量,在JMeter启动时对这个测试计划都是可见的。如果同一个变量在多个 b 中被定义,那么只有最后一个定义会生效。一旦某个线程启动后,那么整个变量集合的初始值就会被复制到该线程中。其他测试元件,例如 c 或者 d 可以被用来重新定义变量,这些重定义仅仅影响当前线程。
一、Http Cookie Manager的作用: 1、自动管理cookie:象浏览器一样的存储和发送Cookie,如果发送一个http请求他的响应中包含Cookie,那么Cookie Manager就会自动地保存这些Cookie并在所有后来发送到该站点的请求中使用这些Cookie的值。每个线程都自己存储cookie的区域。在cookie manager中看不到自动保存的cookie,我们可以在View Results Tree的Request界面看到被发送的Cookie Data。 接受到的Cookie的值能被存储到JMeter 线程变量中(2.3.2版本后的JMeter不自动做这个事情)。要把Cookies保存到线程变量中,要定义属性"CookieManager.save.cookies=true"。线程变量名为COOKIE_ + Cookie名。属性CookieManager.name.prefix= 可以用来修改默认的COOKIE_的值。 2、手动管理Cookie:手动添加Cookie到Cookie Manager,这些Cookie的值被会所有线程共享。 比较简单的做法是使用firefox的firebug导出cookies 然后,在把文件导入到jmeter 二、特别注意: Jmeter官网上有这样一段话: 意思是说: 如果在一个测试计划内有多个Cookie Manager ,Jmeter目前无法指定哪个被使用。所以,一个测试计划内最好只有一个cookie manager。并且,一个manager里的 cookie 并不能被其它manager所引用。所以在使用多个Cookie Managers 时要谨慎。 同理,上面这个规则同样适用于config element下面的其它manager: 官方文档: http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Cookie_Manager
在使用Jmeter进行性能测试时,如果并发数比较大(比如最近项目需要支持1000并发),单台电脑的配置(CPU和内存)可能无法支持,这时可以使用Jmeter提供的分布式测试的功能。 一、Jmeter分布式执行原理: 1、Jmeter分布式测试时,选择其中一台作为调度机(master),其它机器做为执行机(slave)。 2、执行时,master会把脚本发送到每台slave上,slave 拿到脚本后就开始执行,slave执行时不需要启动GUI,我理解它应该是通过命令行模式执行的。 3、执行完成后,slave会把结果回传给master,master会收集所有slave的信息并汇总。 二、执行机(slave)配置: 1、slave机上需要安装Jmeter,具体如何安装这里不详细介绍了。 2、添加环境变量:JMETER_HOME=D:\B_TOOLS\apache-jmeter-2.13,此处为你Jmeter的路径 3、启动bin目录下的:jmeter-server.bat,启动成功如下图: 4、上图上标红的IP和端口会在master里配置时用到。IP就是slave机器IP,端口默认是1099,端口也可以自定义,这里我自定义为1000,这个后面会讲。 5、多台slave的话,重复1~4步骤就好。 三、调度机(master)配置: 1、脚本:简单的一个访问百度的脚本: 2、找到Jmeter的bin目录下jmeter.properties文件,修改如下配置,IP和Port是slave机的IP以及自定义的端口(这里端口我自定义为100,后面会讲如何自定义): remote_hosts=10.13.223.202:1000,10.13.225.12:1000 多台slave之前用","隔开,我这配置了2台,可以看到标红的这个就是上面截图slave的IP和Port. 3、打开Jmeter,选择运行,有运程启动、运程全部启动两个选项: 4、选择远程启动-->10.13.225.12:1000 a) master结果,这里我只启动了10.13.225.12:1000这一台slave,所以只有一个结果(线程数和循环次数都是1): b) slave控制台信息: 5、选择远程启动-->远程全部启动: a) master结果,全部启动,我配置了2台slave,所以有两次执行结果: 四、自定义端口: 上面其实已经实现了Jmeter的分布式测试,这部分主要介绍下如何自定义slave端口: 1、slave:在slave机的Jmeter的bin目录下,找到jmeter.properties文件,修改如下两个配置项,比如我这里修改为1888: server_port=1888 server.rmi.localport=1888 2、启动slave机上的jmeter-server.bat,如下图,端口已经修改为:1888 3、master:修改master机器的jmeter.properties文件: remote_hosts=10.13.223.202:1000,10.13.225.12:1888 4、重启jmeter.bat,如下图,端口已经变了: 五、其它说明: 1、调度机(master)和执行机(slave)最好分开,由于master需要发送信息给slave并且会接收slave回传回来的测试数据,所以mater自身会有消耗,所以建议单独用一台机器作为mater。 2、参数文件:如果使用csv进行参数化,那么需要把参数文件在每台slave上拷一份且路径需要设置成一样的。 3、每台机器上安装的Jmeter版本和插件最好都一致,否则会出一些意外的问题。
一、Jmeter重要组件: 1)配置元件---Config Element: 用于初始化默认值和变量,以便后续采样器使用。配置元件大其作用域的初始阶段处理,配置元件仅对其所在的测试树分支有效,如,在同一个作用域的任何采样器前。 2)前置处理器--- Pre Processors: 前置处理器会在采样器发出请求之前做一些特殊操作。如果前置处理器附着在某个采样器之下,那么它只会在该采样器运行之前执行。前置处理器通常用于在采样器发出请求前修改采样器的某些设置,或者更新某些变量的值(这些变量不在服务器响应中获取值)。 3) 计时器---Timer: 定时器会让作用域内的每一个采样器都在执行前等待一个固定时长,如果不设定这种延迟,JMeter可能会在短时间内产生大量访问请求,导致服务器被大量请求所淹没。如果为线程组添加了多个定时器,那么JMeter会将这些定时器的时长叠加起来,共同影响作用域范围内的采样器。定时器可以作为采样器或者逻辑控制器的子项,目的是只影响作用域内的采样器。 4) 采样器---sampler: 采样器告诉JMeter发送一个请求到指定服务器,并等待服务器的请求。采样器会按照其在测试树中的顺序去执行,还可以用逻辑控制器来改变采样器运行的重复次数。 5)后置处理器---Post Processors: 后置处理器会在采样器发出请求之后做一些特殊操作。如果后置处理器附着在某个采样器之下,那么它只会在该采样器运行之后执行。后置处理器通常被用来处理服务器的响应数据,特别是服务器响应中提取数据。 6)断言---Assertions: 用户可以使用断言来检查从服务器获得的响应内容。通过断言可以测试服务器返回的响应与测试人员的期望是否相符 7)监听器---Listener: 监听器提供了对JMeter在测试期间收集到的信息的访问方法。"图形结果"监听器会将系统响应时长绘制在一张图片之中。"查看结果树"监听器会展示采样器请求和响应的细节,还可以将测试数据导入到文件之中,以供后续分析。 8) 逻辑控制器---Controller: 逻辑控制器可以帮助用户控制JMeter的测试逻辑,特别是何时发送请求。逻辑控制器可以改变其子测试元件的请求执行顺序。 二、组件执行顺序: 测试计划的元素执行是有序的,通过以下方式执行:1–配置元件(Config Element)2–前置处理器(Pre Processors)3–定时器(Timer)4–取样器(sampler)5–后置处理器(Post Processors,只在有结果可用情况下执行)6–断言(Assertions,只在有结果可用情况下执行)7–监听器(Listener,只在有结果可用情况下执行) 三、组件作用域: 元件收集其作用范围的每一个sampler元件的信息并呈现,在jmeter中,元件的作用域是靠测试计划的的树型结构中元件的父子关系来确定的,作用域的原则是: 采样器(sampler):元件不和其它元件相互作用,因此不存在作用域的问题。 逻辑控制器(Logic Controller):元件只对其子节点中的取样器 和 逻辑控制器作用。 除采样器 和 逻辑控制器 元件外,其他6类元件,如果是某个sampler的子节点,则该元件只对其父子节点起作用。 除采样器和逻辑控制器元件外的其他6类元件,如果其父节点不是sampler ,则其作用域是该元件父节点下的其他所有后代节点(包括子节点,子节点的子节点等)。 四、特殊说明: 配置元件(Config Elemnet)-->用户自定义变量组件(User Defined Variables):这个组件不管放在哪个位置,它定义的变量都会被整个线程所共享。 例如: 下面这个例子,测试计划定义如下: 1、定义了三个sampler:one、Debug Sampler、two 2、在one下面定义了一个用户自定义变量:在这里添加了一个变量,名为hello,值为world 3、一个监听器:查看结果树 目的:测试在sampler one下定义的变量是否能被sampler two和debug sampler所引用 one: User Defined Variables: two: 运行结果: 由上可知:在one下面定义的用户变量,在debug sampler和two处都能正常使用。 参考: http://www.cnblogs.com/fnng/archive/2012/12/27/2836506.html
一、环境准备: 1、JDK:http://www.oracle.com/technetwork/java/javase/downloads/index.html 2、Jmeter:http://jmeter.apache.org/download_jmeter.cgi 3、Ant:http://ant.apache.org/bindownload.cgi 4、Jenkins:http://jenkins-ci.org/ 具体可参见我另一篇博客:http://www.cnblogs.com/puresoul/p/4808416.html 二、Jemter脚本准备: 1、脚本目录:D:\B_TOOLS\apache-jmeter-2.13\demo 2、脚本内容:都是简单的访问百度或google首页 baidu.jmx google.jmx 三、ANT的build.xml代码准备: build3.xml 1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <project name="ant-jmeter-test" default="run" basedir="."> 4 <tstamp> 5 <format property="time" pattern="yyyyMMddhhmm" /> 6 </tstamp> 7 8 <property environment="env"/> 9 <property name="ReportName" value="TestReport" /> 10 <!-- 需要改成自己本地的 Jmeter 目录--> 11 <property name="jmeter.home" value="D:\B_TOOLS\apache-jmeter-2.13" /> 12 <!-- jmeter生成jtl、html格式的结果报告的路径--> 13 <property name="jmeter.result.dir" value="${env.WORKSPACE}/results/${env.BUILD_ID}" /> 14 <!-- 生成的报告的前缀--> 15 <property name="jmeter.result.jtlName" value="${jmeter.result.dir}/${ReportName}.jtl" /> 16 <property name="jmeter.result.htmlName" value="${jmeter.result.dir}/${ReportName}.html" /> 17 18 <target name="run"> 19 <echo message="start..."/> 20 <antcall target="clean" /> 21 <antcall target="test" /> 22 <antcall target="report" /> 23 </target> 24 25 <target name="clean"> 26 <mkdir dir="${env.WORKSPACE}/results/${env.BUILD_ID}" /> 27 </target> 28 29 <target name="test"> 30 <taskdef name="jmeter" classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask" /> 31 <jmeter jmeterhome="${jmeter.home}" resultlog="${jmeter.result.jtlName}"> 32 <!-- 声明要运行的脚本"*.jmx"指包含此目录下的所有jmeter脚本--> 33 <testplans dir="D:\B_TOOLS\apache-jmeter-2.13\demo" includes="*.jmx" /> 34 35 <property name="jmeter.save.saveservice.output_format" value="xml"/> 36 </jmeter> 37 </target> 38 39 <target name="report"> 40 <xslt in="${jmeter.result.jtlName}" 41 out="${jmeter.result.htmlName}" 42 style="${jmeter.home}/extras/jmeter-results-detail-report_21.xsl" /> 43 <!-- 因为上面生成报告的时候,不会将相关的图片也一起拷贝至目标目录,所以,需要手动拷贝 --> 44 <copy todir="${jmeter.result.dir}"> 45 <fileset dir="${jmeter.home}/extras"> 46 <include name="collapse.png" /> 47 <include name="expand.png" /> 48 </fileset> 49 </copy> 50 </target> 51 </project> 四、配置Jenkins Job并运行: 1、job配置如下: 2、job运行结果: 1 Started by user anonymous 2 Building in workspace D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace 3 [demo] $ cmd.exe /C '"ant.bat -file build3.xml run && exit %%ERRORLEVEL%%"' 4 Buildfile: build3.xml 5 6 run: 7 [echo] start... 8 9 clean: 10 [mkdir] Created dir: D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace\results\15 11 12 test: 13 [jmeter] Executing test plan: D:\B_TOOLS\apache-jmeter-2.13\demo\baidu.jmx ==> D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace\results\15\TestReport.jtl 14 [jmeter] Creating summariser <summary> 15 [jmeter] Created the tree successfully using D:\B_TOOLS\apache-jmeter-2.13\demo\baidu.jmx 16 [jmeter] Starting the test @ Tue Sep 22 15:50:33 CST 2015 (1442908233010) 17 [jmeter] Waiting for possible shutdown message on port 4445 18 [jmeter] summary + 1 in 1s = 2.0/s Avg: 254 Min: 254 Max: 254 Err: 0 (0.00%) Active: 1 Started: 1 Finished: 0 19 [jmeter] summary + 5 in 1s = 7.3/s Avg: 131 Min: 96 Max: 196 Err: 0 (0.00%) Active: 0 Started: 1 Finished: 1 20 [jmeter] summary = 6 in 1.2s = 5.0/s Avg: 151 Min: 96 Max: 254 Err: 0 (0.00%) 21 [jmeter] Tidying up ... @ Tue Sep 22 15:50:34 CST 2015 (1442908234310) 22 [jmeter] ... end of run 23 [jmeter] Executing test plan: D:\B_TOOLS\apache-jmeter-2.13\demo\google.jmx ==> D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace\results\15\TestReport.jtl 24 [jmeter] Creating summariser <summary> 25 [jmeter] Created the tree successfully using D:\B_TOOLS\apache-jmeter-2.13\demo\google.jmx 26 [jmeter] Starting the test @ Tue Sep 22 15:50:35 CST 2015 (1442908235240) 27 [jmeter] Waiting for possible shutdown message on port 4445 28 [jmeter] summary + 1 in 1s = 1.9/s Avg: 253 Min: 253 Max: 253 Err: 1 (100.00%) Active: 1 Started: 1 Finished: 0 29 [jmeter] summary + 5 in 1.1s = 4.4/s Avg: 209 Min: 97 Max: 420 Err: 0 (0.00%) Active: 0 Started: 1 Finished: 1 30 [jmeter] summary = 6 in 2s = 3.6/s Avg: 216 Min: 97 Max: 420 Err: 1 (16.67%) 31 [jmeter] Tidying up ... @ Tue Sep 22 15:50:36 CST 2015 (1442908236992) 32 [jmeter] ... end of run 33 34 report: 35 [xslt] Processing D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace\results\15\TestReport.jtl to D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace\results\15\TestReport.html 36 [xslt] Loading stylesheet D:\B_TOOLS\apache-jmeter-2.13\extras\jmeter-results-detail-report_21.xsl 37 [copy] Copying 2 files to D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace\results\15 38 39 BUILD SUCCESSFUL 40 Total time: 5 seconds 41 [workspace] $ cmd /c call D:\Users\heman793\AppData\Local\Temp\hudson4765606743104861298.bat 42 43 D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace>echo D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace 44 D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace 45 46 D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace>echo 15 47 15 48 49 D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace>cd results 50 51 D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace\results>cd 15 52 53 D:\B_TOOLS\jenkins\jobs\TestJenkins\workspace\results\15>exit 0 54 Finished: SUCCESS 3、在job的workspace目录下会生成结果报告: 4、TestReport.html: 更新补充: 上面生成的报告有如下两个问题,解决办法参见Jmeter自带报告优化(一): 1、Date report这里的时间没有正确显示出来 2、Summary里的字段Min Time和Max Time显示的是NaN,没有显示正确的时间。 五、配置发送邮件功能 1、自已写一个发送邮件的功能并打成sendmail.jar包,放在job的workspace目录中 2、jenkins增加构建步骤 a)进入到测试报告的目录 b) 调用sendmail.jar命令发送邮件 说明: 1、由build3.xml的第12、13行可知,报告文件生成目录为:${env.WORKSPACE}/results/${env.BUILD_ID},所以这里我要先cd到具体执行的那个build_id目录下。 2、我们也可以把上面的两行命令写在成一个批处理文件,例如我第1步有个sendmail.bat文件就是的,然后调用时直接写sendmail.bat就好了。 另外,我本文所有脚本都在我本地,其实更好的办法是使用SVN统一管理,这里就不介绍了,感觉的可以自己研究下。
一、查看Jenkins有哪些环境变量 1、新建任意一个job 2、增加构建步骤:Execute shell 或 Execute Windows batch command 3、点击输入框下方的“可用环境变量” 4、可以看到有如下变量供使用: 变量名 解释 BUILD_NUMBER The current build number, such as "153" BUILD_ID The current build ID, identical to BUILD_NUMBER for builds created in 1.597+, but a YYYY-MM-DD_hh-mm-ss timestamp for older builds BUILD_DISPLAY_NAME The display name of the current build, which is something like "#153" by default. JOB_NAME Name of the project of this build, such as "foo" or "foo/bar". (To strip off folder paths from a Bourne shell script, try: ${JOB_NAME##*/}) BUILD_TAG String of "jenkins-${JOB_NAME}-${BUILD_NUMBER}". Convenient to put into a resource file, a jar file, etc for easier identification. EXECUTOR_NUMBER The unique number that identifies the current executor (among executors of the same machine) that’s carrying out this build. This is the number you see in the "build executor status", except that the number starts from 0, not 1. NODE_NAME Name of the slave if the build is on a slave, or "master" if run on master NODE_LABELS Whitespace-separated list of labels that the node is assigned. WORKSPACE The absolute path of the directory assigned to the build as a workspace. JENKINS_HOME The absolute path of the directory assigned on the master node for Jenkins to store data. JENKINS_URL Full URL of Jenkins, like http://server:port/jenkins/ (note: only available if Jenkins URL set in system configuration) BUILD_URL Full URL of this build, like http://server:port/jenkins/job/foo/15/ (Jenkins URL must be set) SVN_REVISION Subversion revision number that's currently checked out to the workspace, such as "12345" SVN_URL Subversion URL that's currently checked out to the workspace. JOB_URL Full URL of this job, like http://server:port/jenkins/job/foo/ (Jenkins URL must be set) 二、使用Jenkins的内置变量 1、在Execute shell 或 Execute Windows batch command文本框中使用,使用方法:%变量名%,如下图 2、结合Ant,在build.xml文件中使用: 1、添加如下第4行代码:<property environment="env"/> 2、使用方法:${env.WORKSPACE} 1 <?xml version="1.0" encoding="UTF-8"?> 2 3 <project name="ant-test" default="run" basedir="."> 4 <property environment="env"/> 5 6 <target name="clean"> 7 <mkdir dir="${env.WORKSPACE}/results/${env.BUILD_ID}" /> 8 </target> 9 10 </project>