qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

从测试员到测试负责人

 从测试员到测试负责人的本质改变是开始承担管理责任,测试负责人作为组织中的最基层管理者,除了执行相关能力的继续提升外,需要开始担任部分管理职能。从一个执行者开始转变为一个管理者,主要的变化有以下几点:
  1:责任范围的改变
  纯粹的执行者原则上只需要为自己的执行工作负责即可;而管理者需要对自己管理范围内的所有工作负责,即使不是自己执行的工作,也要负管理责任。
  对于执行者,我们会希望他们有超出自己职责范围的责任心,这会有助于其个人能力的发展和进步,也会提升部门整体的工作效率和绩效,但这并非职责要求必须达到的,所以在评价员工的时候,会有不合格、合格、超出预期几个档次。
  对于管理者,对责任心的要求则成为基本要求。通常也只有获得超出预期评价的员工才可能会被提拔为管理者。
  2:责任范围的变化直接带来具体工作方式的变化
  作为基层管理者,实际工作中的执行工作仍然占了相当大的比例,但新增的管理工作内容虽然比例相对比较小,但却是评价一个管理者的重要部分。
  首先是内部工作分配,要做好内部工作分配有以下几点需要注意:
  A:首先是发现工作,管理者要自主发现工作内容,而不是等待上级分配;
  B:然后是对下属的了解,充分了解下属才能把合适的工作分配给合适的人;
  C:维持部门工作士气,限制负面情绪和负能量的产生和传播,创造和传播正面情绪和正能量。
  D:工作成果的验收和检验,考验管理者对自己部门的掌控力,也是部门绩效的最终成果。
  其次是外部协调,为本部门的工作开展创造一个良好的外部环境:
  A:调节自身测试部门和其他部门的关系
  B:调解其他部门之间的关系
  C:注意以上两条的最终原则:团队的稳定和项目的成功
  然后是协助上级,完成上级指派的任务:
  基层管理者除了自身的管理者身份,同时很大程度上也是被管理者,需要完成上级指派的各种任务,和纯粹的执行者的差别只是可以利用自己管理范围内的资源去完成上级指派的任务,而不一定必须亲自完成。
  包括但不限于,例如:项目间的测试资源调配帮忙。

3:必要的工作技巧和方法:
  1:在部门内部建立威信
  A:展示自身工作能力
  B:展示自身职业素养和专业素养
  C:帮助下属提升
  D:任何时候保持沉稳、冷静;主管的心乱了,整个部门就乱了。
  2:获得项目组其他部门特别是部门主管的认可
  A:展示自身的责任心
  B:展示自身工作能力
  C:展示自身职业素养和专业素养
  D:帮助其他部门解决问题
  3:眼界的开阔
  A:关注行业和专业动态
  B:把A转化为对项目的实质性帮助

posted @ 2014-06-25 11:32 顺其自然EVO 阅读(204) | 评论 (0)编辑 收藏

PC端稳定性测试探索

 在PC客户端软件测试中,稳定性测试是必不可少的一项测试内容。一般在功能测试已经测试完成,缺陷完全修复完成以后进行。
  稳定性测试是在保证客户端功能完整正确的前提下,通过对软件稳定性的测试可以观察在一个运行周期内、一定的压力条件下,软件的出错机率、性能劣化趋势等。进而大大减少软件上线后的崩溃卡死等现象,为软件的逐步优化提供方向及验证。
  测试方法:通过自动化脚本,长时间运行客户端某些功能或长时间开关客户端,看客户端是否存在Crash现象,同时查看内存、CPU等性能指标。
  一款PC客户端软件,它的稳定性测试需求基本包括:
  长时间运行及各种操作下,软件的稳定性以及各种性能指标的劣化趋势。
  多进程或多线程运行时的稳定性。
  不同操作系统,在不同软件环境下运行的稳定性。
  具体来讲:
  长时间:一般都要24h以上,要求高点的要24h*3;
  不同操作系统:基本上都需要覆盖下面系统:Winxp、Win7 x86、Win7 x64、win8 x64、Win 8.1;
  不同软件环境下:主要是指不同的杀毒软件和安全软件环境下;
  步骤:
  确定稳定性测试需求,包括:需要覆盖的功能点、系统环境和软件环境、测试时间长度
  开发自动化运行脚本
  执行脚本,进行性能监控
  分析执行结果
  自动化脚本
  稳定性测试必须要用自动化测试脚本,标准控件可以用QTPLoadRunner来进行,可以方便的来进行自动化脚本开发。
  但由于QTP或LoadRunner都是收费软件,很贵,大部分公司都没有license,而且它对非标准控件的支持很差。现在我们用一些开源的工具来替代,这边用Autoit来编写自动化脚本。
  学习参考网址:http://www.autoitx.com/
  AutoIt ,这是一个使用类似BASIC脚本语言的免费软件,它设计用于Windows GUI(图形用户界面)中进行自动化操作。它利用模拟键盘按键,鼠标移动和窗口/控件的组合来实现自动化任务。
  优点
  - 轻量级(官方发布包10M左右),编译成可执行文件后在没有安装 AutoIt 的机器上也可直接运行
  - 免费,不需要许可证 - 有丰富的函数库(标准函数库和自定义函数库) - 基于Win32 API,方便扩展
  - 有完善的帮助文档和丰富的论坛资源
  例子
  用一个简单的客户端开关稳定性测试来看看怎么运行的:
  开关测试属于稳定性测试里的一种,将客户端长时间不断地开启和关闭,看客户端是否会Crash,产生dump文件。
  看下面代码:
;定义变量
Dim $Sum,$i
$Sum=0
$i=1
;循环开关次数
While $i<=86400
$Sum=$Sum+$i
$i=$i+1
Run("C:\Nep\debug\GacRunnerB_D.exe")
WinWait("NEPSingle")
Sleep(1000)
;取得进程pid
$iPid = WinGetProcess("NEPSingle")
;关闭此进程
ProcessClose($iPid)
WEnd
 执行
  稳定性测试不同于一般的功能测试,属于概率学测试,并不是这次没测出来就是没问题,所以需要长时间运行,多个系统,多种软件环境中进行多次测试,尽可能的提供可靠性。
  结果
  从稳定性测试的结果的判断从下面几个方向判断:
  判断是否Crash:可以通过dump文件判断是否有crash的现象,可以将产生的dump发给开发分析crash原因
  判断是否性能劣化:在稳定性测试的同时通过性能监控工具对内存、cpu、句柄等性能参数进行监控,查看性能是否出问题。

posted @ 2014-06-25 11:31 顺其自然EVO 阅读(1901) | 评论 (0)编辑 收藏

iOS及Android自动化实践

 App:网易看游戏(Xone)
  工具:appium 1.0
  Appium 1.0较以往的版本有了比较大的变化。
  1.xpath路径改变
  Before:/window[1]/navigationBar[1]/button[4]
  Current://UIAApplication[1]/UIAWindow[1]/UIANavigationBar[1]/UIAButton[4]
  2.Capability参数名称改变
Before:
desiredCapabilities.setCapability(CapabilityType.PLATFORM, "iOS");
desiredCapabilities.setCapability(CapabilityType.VERSION, "7.0");
Current:
desiredCapabilities.setCapability("platformVersion", "7.0");desiredCapabilities.setCapability("platformName", "iOS");
  3.Appium客户端UI变化(提供更丰富的参数选择)
  4.稳定性提供,客户端未崩溃过。
  等等
  接下来简单讲下具体实践过程吧
  1.项目结构,如图
  page:获取UI元素类
  test:用例类,即测试
  util:封装大部分的公共方法
  assertion:断言类
  以testng框架为基础,ant编译执行,实现了每日构建运行。
2.编码,贴下通行证登录模块的代码,供参考
  测试类:PassportLogin
public class PassportLogin extends BaseTest {
private static Logger log = Logger.getLogger(PassportLogin.class);
@DataProvider(name = "passportLoginData")
public static Object[][] passportLoginData() {
return new Object[][] {
{ "正确的网易通行证登录", "xxxxx@163.com", "xxxxx", "" },
{ "非网易账号的网易通行证登录", "xxx@qq.com", "xxxx", "" },
{ "网易通行证登录,密码错误", "xxxx@163.com", "xxx",
"用户名或密码错误" },
{ "不输入账号和密码", "", "", "用户名不能为空" },
{ "不输入密码", "xxx@163.com", "", "密码不能为空" },
{ "不输入账号", "", "xxxx", "用户名不能为空" },
{ "错误的网易通行证登录", MyRandom.getRandomString(10) + "@163.com",
MyRandom.getRandomString(6), "用户名或密码错误" } };
}
@BeforeClass
public void setUp() {
driver = new Orange();
mainPage = new MainPage(driver);
account = new Account(driver);
as = new AssertSettings(driver);
usPage = new UserSettingsPage(driver);
homePage = new HomePage(driver);
mainPage.enterMainPage();
mainPage.enterLogin();
account.logoutTrue();
}
@AfterClass
public void tearDown() {
driver.quit();
}
@AfterMethod
public void end() throws InterruptedException {
log.info("-------------------------------------------------------------------");
}
@Test(dataProvider = "passportLoginData")
public void passportLoginTest(String testName, String passport,
String password, String errorCode) throws InterruptedException {
log.info("测试内容:" + testName);
mainPage.enterLogin();
account.login(passport, password);
if (errorCode != "") {
boolean b = as.assertLogin(errorCode);
driver.sleep(3000);
mainPage.flickToRight();
mainPage.closePage();
Assert.assertTrue(b);
} else {
mainPage.enterLogin();
homePage.settingsClick();
usPage.passportClick();
account.logout();
}
}
}
由于涉及到了多个page,这里只贴部分Page类,如Account类,用于获取登录操作
public class Account extends BasePage {
/**
* @Title: Account
* @Description: TODO
* @param @param driver
* @throws
*/
public Account(Orange driver) {
super(driver);
// TODO Auto-generated constructor stub
}
/**
* @Title: login
* @Description: TODO
* @param @param driver
* @return void
* @throws
*/
public void login() {
driver.clickOnElement(By.name("网易通行证登录"));
driver.sendKeys(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIATextField[1]"),
PropertiesHandle.readValue("passport_2"));
driver.sendKeys(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIASecureTextField[1]"),
PropertiesHandle.readValue("password"));
driver.clickOnElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIAButton[1]"));
}
/**
* @Title: login
* @Description: TODO
* @param @param driver
* @param @param passport
* @param @param password
* @return void
* @throws
*/
public void login(String passport, String password) {
driver.clickOnElement(By.name("网易通行证登录"));
driver.sendKeys(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIATextField[1]"), passport);
driver.sendKeys(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIASecureTextField[1]"), password);
driver.clickOnElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIAButton[1]"));
}
/**
* @Title: login
* @Description: TODO
* @param @param type
* @param @param passport
* @param @param password
* @return void
* @throws
*/
public void login(String type, String passport, String password) {
driver.clickOnElement(By.name(type));
driver.sendKeys(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIATextField[1]"), passport);
driver.sendKeys(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIASecureTextField[1]"), password);
driver.clickOnElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIAButton[1]"));
}
/**
* @Title: login
* @Description: TODO
* @param @param type
* @return void
* @throws
*/
public void login(String type) {
driver.clickOnElement(By.name(type));
}
/**
* @Title: logout
* @Description: TODO
* @param @param driver
* @return void
* @throws
*/
public void logout() {
driver.clickOnElement(By.name("退出当前帐号"));
driver.clickOnElement(By.name("确定"));
}
}
  主要的公共类:Orange,主要借鉴了孔庆云同学已经封装好的方法,并进行一些改进后直接使用,方便快捷。
  目前Appium已经到了1.1版本,这款自动化工具还是不错的,跨平台,跨语言支持都比较好,稳定性也在逐步提升。

posted @ 2014-06-25 11:30 顺其自然EVO 阅读(273) | 评论 (0)编辑 收藏

casperjs进行web功能自动化测试demo

  通过一周多的学习和总结,终于掌握了casperjs用于自动化的方法,填平了大大小小的各种坑。
  casperjs是一个新兴的测试框架,网上资料很少,基本上靠翻译英文资料。
  贡献出来,供大家参考:
//page.js,存放页面元素
//c表示通过css选择元素,x表示通过xpath选择元素
var baseurl="http://www.cnblogs.com/reach296/";
var base={
//首页
url:baseurl,
c:{
登录表单:'form#login',
登录按钮:'.btn'
}
};
var index={
//登录后成功后跳转页
url:baseurl+"/seven/index"
};
var sidebar={
//左边框
url:baseurl+"/seven/sidebar.jsp",
x:{
应用库:"//span[contains(text(),应用库)]",
应用分类:"//ul[@class='submenu']/li/a[1]"
}
};
var category_list={
//应用分类page
url:baseurl+"/seven/app/category-list",
c:{
名称:'td.sorting_1'
},
x:{
表格:'//*[@id="sample-table-2"]/tbody/tr',
名称:'//*[@id="sample-table-2"]/tbody/tr/td[1]',
海报:'//*[@id="sample-table-2"]/tbody/tr/td[2]',
编辑:'//*[@id="sample-table-2"]/tbody/tr/td[3]'
}
}
//common.js,存放全局变量和方法
var path={
capture:'cms/capture/',
lib:'cms/lib/'
};
var cap={
clipRect:{top: 0,left: 0,width: 1024,height: 768},
// clipRect:{width: 1024,height:768},
imgOptions:{format: 'jpg',quality:100}
};
var account={'loginName':'reachwang','passwd':'test12345'};
function get_menu_links(){
//获取一级模块
var links = window.frames[0].document.getElementsByTagName("frame")[0].contentDocument.getElementsByClassName("menu-text");
return Array.prototype.map.call(links, function(e) {
return e.innerText;
});
};
function get_submenu_links(){
//获取二级模块
var links = window.frames[0].document.getElementsByTagName("frame")[0].contentDocument.querySelectorAll('.submenu a');
return Array.prototype.map.call(links, function(e) {
return (e.innerText).replace(/(^\s*)|(\s*$)/g, "");
});
};
//应用分类测试用例,检查应用分类页面是否正常展示,分类数据是否存在
casper.test.begin('应用分类测试用例',function suite(test) {
casper.options.verbose = true;
casper.options.logLevel = "debug";
casper.options.viewportSize={width: 1024, height: 768};
casper.options.waitTimeout=20000;
// casper.options.clientScripts=[
// path.lib+'common.js'
// ];
casper.test.comment('检查应用分类页面是否正常展示,分类数据是否存在');
casper.start(base.url, function() {
this.echo("1、打开登录页面");
test.assertHttpStatus(200,"检查http请求状态");
});
casper.waitForSelector(base.c.登录按钮, function() {
this.echo("2、登录页面截图");
this.capture(path.capture+"登录页面.jpg",cap.clipRect, cap.imgOptions);
});
casper.then(function() {
this.echo("3、登录页面检查");
test.assertTitle("TCL CMS", "标题正确");
test.assertExists(base.c.登录表单, "帐号登录表单存在");
this.echo("4、输入帐号和密码");
this.fill(base.c.登录表单, account, true);
this.echo("5、点击登录按钮");
test.assertExists(base.c.登录按钮, "登录按钮存在");
this.mouse.click(base.c.登录按钮);
});
casper.waitForUrl(index.url,function(){
test.assertHttpStatus(200,"跳转到登录完成页");
this.capture(path.capture+'跳转到登录完成页.jpg',cap.clipRect, cap.imgOptions);
});
casper.withFrame(0,function(){
this.echo("切换到mian frame里");
casper.withFrame(0,function(){
this.echo("切换到mian frame下的sider frame里");
this.echo("6、点击应用库");
this.click({type: 'xpath',path:sidebar.x.应用库});
this.echo("7、点击应用分类");
this.click({type: 'xpath',path:sidebar.x.应用分类});
});
});
casper.waitForUrl(index.url,function(){
test.assertHttpStatus(200,"跳转到应用分类页");
this.capture(path.capture+'打开应用分类.jpg',cap.clipRect, cap.imgOptions);
});
casper.withFrame(0,function(){
this.echo("切换到mian frame里");
casper.withFrame(1,function(){
this.echo("应用分类页面")
test.assertExists({type: 'xpath',path:category_list.x.表格},"表格检查");
test.assertExists(category_list.c.名称,"名称字段检查");
test.assertExists({type: 'xpath',path:category_list.x.海报},"海报字段检查");
test.assertExists({type: 'xpath',path:category_list.x.编辑},"编辑字段检查");
});
});
casper.run(function() {
test.done();
});
});

posted @ 2014-06-25 11:28 顺其自然EVO 阅读(1221) | 评论 (0)编辑 收藏

5分钟实现VS2010整合NUnit进行单元测试

 1、下载安装NUnit(最新win版本为NUnit-2.6.0.12051.msi) http://www.nunit.org/index.php?p=download
  2、下载并安装VS的Visual Nunit 2010 插件  http://visualstudiogallery.msdn.microsoft.com/c8164c71-0836-4471-80ce-633383031099
  注:可通过VS的“视图”->“其他窗口”找到并打开该插件(快捷键:Ctrl+F7)
  3、新建测试项目UnitTestApp(示例为简单的控制台应用程序),引入nunit.framework类库(默认安装后文件所在路径:C:\Program Files \NUnit 2.6\bin\framework\nunit.framewor.dll)
  4、添加Calculator类,实现一个简单加法和获取单例方法
namespace UnitTestApp
{
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
private static readonly object objSync = new object();
private static Calculator instance = null;
public static Calculator GetInstance()
{
if (instance == null)
{
lock (objSync)
{
if (instance == null)
{
instance = new Calculator();
}
}
}
return instance;
}
}
}
5、新增NUnitTest类进行单元测试
using NUnit.Framework;
namespace UnitTestApp
{
[TestFixture]
public class NUnitTest
{
[Test]
public void AddTest()
{
var calc = new Calculator();
var result = calc.Add(1, 1);
Assert.AreEqual(2, result);
}
[Test]
public void AddTestFailure()
{
var calc = new Calculator();
var result = calc.Add(1, 1);
Assert.AreEqual(10, result);
}
[Test]
public void SingtonTest1()
{
var calc = Calculator.GetInstance();
Assert.IsNull(calc);
}
[Test]
public void SingtonTest2()
{
var calc1 = Calculator.GetInstance();
var calc2 = Calculator.GetInstance();
Assert.IsTrue(object.Equals(calc1, calc2));
}
}
}
  编译控制台项目,点击Visual Nunit 插件的“Run”按钮,然后一切清静了。
  注:在上面的代码中引用 NUnit.Framework,使用TestFixture标注这是用于测试的类,在其中使用 Test表示具体的测试用例。可以看到单元测试中最重要的是断言,其他完全交给框架自动化。测试结果可以通过插件及时看到:

posted @ 2014-06-25 11:27 顺其自然EVO 阅读(218) | 评论 (0)编辑 收藏

持续集成之路—服务层的单元测试

 在完成了数据访问层的单元之后,接下来看如何编写服务层(Service)的单元测试。服务层应该是整个系统中得重中之重,严密的业务逻辑设计保证了系统稳定运行,所以这一层的单元测试也应该占很大比重。虽然一般情况下单元测试应该尽量通过mock剥离依赖,但是由于在当前的项目中数据访问层使用spring-data框架,并没有包含太多的逻辑,因此我就把服务层和数据访问层放在做了一个伪单元测试。
  一、一般逻辑的单元测试。
  这里采用的方式和数据访问层几乎是一样的,主要包含三步:
  1. 通过@DatabaseSetup指定测试用数据集
  2. 执行被测试方法
  3. 通过Dao从数据库中查询数据验证执行结果
  假设要被测试的代码方法是:
@Service
@Transactional(readOnly = true)
public class ShopServiceImpl extends BaseService implements ShopService{
private Logger logger = LoggerFactory.getLogger(ShopServiceImpl.class);
@Transactional(readOnly = false)
public Floor addFloor(String buildingName, int floorNum, String layout) {
//如果已经存在对应的楼层信息,则抛出已经存在的异常信息
Floor floor = floorDao.findByBuildingNameAndFloorNum(buildingName, floorNum);
if (floor != null) {
throw new OnlineShopException(ExceptionCode.Shop_Floor_Existed);
}
//如果不存在对应的商场信息,则添加新的商场
Building building = buildingDao.findByName(buildingName);
if (building == null) {
building = new Building();
building.setName(buildingName);
buildingDao.save(building);
}
//添加并返回楼层信息
floor = new Floor();
floor.setBuilding(building);
floor.setFloorNum(floorNum);
floor.setMap(layout);
floorDao.save(floor);
return floor;
}
}
  其对应的接口是:
  public interface ShopService {
  public Floor addFloor(String buildingName, int floorNum, String layout);
  }

这段逻辑代码的意思十分简单和直白,那么要编写的单元的测试必须要包含所有分支情况:a. 商场和楼层信息都存在的,抛出异常 b. 商场存在,而楼层不存在, 楼层信息都被添加的。 c.  商场和楼层都不存在,全部新增。这里就以第一种情况为例,先准备测试数据:
  <?xml version="1.0" encoding="UTF-8"?>
  <dataset>
  <building id="1" name="New House"/>
  <floor id="1" building="1" floor_num="2"/>
  </dataset>
  接着编写测试用例,注意要必须得注解不能忘掉:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-test.xml")
@Transactional
@TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
CustomTransactionDbUnitTestExecutionListener.class,
ForeignKeyDisabling.class})
public class ShopServiceTest {
@Autowired
private ShopService shopService;
@Test
@DatabaseSetup("shop/ShopService-addFloorExistException-dataset.xml")
public void testAddFloorExistException(){
try {
shopService.addFloor("New House", 2, "");
fail();
} catch(Exception e){
assertTrue(e instanceof OnlineShopException);
assertEquals(ExceptionCode.Shop_Floor_Existed.code(), ((OnlineShopException)e).getCode());
}
}
}
  这个测试和数据访问层的测试看起来没有什么两样。
  二、使用Mock对象隔离第三方接口
  软件开发中一般都存在和第三方集成的情况,比如调用新浪的认证、百度的地图等等。那么在编写测试的时候,基于效率的考虑,一般情况不会真的去调用这些远程API(当然应该有其他测试可以及时发现第三方接口的变化),而是假定它们一直会返回预期的结果。这个时候就需要用到mock对象,来模拟这些API产生相应的结果。
  在这里,我是用了mockito,使用十分方便。假如现在用户登录时,需要去第三方系统验证,那么现在来看如何对这个场景进行测试。还是先来看被测试的方法:
  private boolean validateUser(String inputName, String inputPassword) {
  return thirdPartyAPI.authenticate(inputName, inputPassword);
  }
  其中thirdPartyAPI就是第三方用来认证的API。下面来看测试代码:
public class UserServiceTest {
@Autowired
private UserService userService;
private ThirdPartyAPI mockThirdPartyAPI = mock(ThirdPartyAPI.class);
@Test
public void testLogin(){
//指定mock对象特定操作的返回结果
when(mockThirdPartyAPI.authenticate("jiml", "jiml")).thenReturn(true);
//通过Setter用mock对象替换由Spring初始化的第三方依赖
((UserServiceImpl)userService).setThirdPartyAPI(mockThirdPartyAPI);
boolean loginStatus = userService.login("jiml", "jiml");
assertTrue(loginStatus);
}
}
  其实服务层的测试并没有太多的新东西,而最关键的问题是如何把逻辑中各个分支都能测试到,使测试真正起到为软件质量保驾护航的作用。

posted @ 2014-06-25 11:26 顺其自然EVO 阅读(221) | 评论 (0)编辑 收藏

我怎么做性能测试

 今天和同事交流关于性能测试的东西,以前也做过性能测试,突然想写点自己关于如何做性能测试的认识。
  基于B/S架构的系统,利用loadrunner做性能测试,利用nmon监控系统资源(用linux自带的top,vmstat等命令也可以,写一些简单的shell脚本就行了)。
  那么到底该怎么去做性能测试呢?
  1、首先要了解被测系统的结构和有关知识的储备。
  了解了被测系统,在后期性能出现异常的时候,定位就相对容易一些;而且知道在测试的过程中需要监控什么。
  一个简单B\S系统结构图:
  该系统有一下及部分组成:
  APP:一台nginx,兼做web和应用服务器
  Memcached:负责做数据缓存
  lucene:负责做搜索
  RabbitMQ:负责某些业务的队列处理
  mysql:数据库服务器,一个主库,一个从库
  从以上系统结构来看,要搭建和维护性能测试环境,需要的一些必要的知识。
  对于APP:需要了解nginx的相关知识,怎么修改配置,在哪里看日志
  对于Memcached:怎么搭建Memcached,怎么查看命中率,Memcached的作用是什么
  lucene:这个lucene是干什么用的,要怎么配置
  RabbitMQ:MQ要如何配置,都那些业务用到了MQ。
  Mysql:如何配置主从,为什么要配置主从,主从如何同步等等
  在搭建环境的过程中肯定会遇到这样或那样的问题,要自己找资料,或者相关的开发人员一起解决,并注意做笔记,防止以后同样的问题再出现。
  2、了解了系统结构,开始搭建测试环境,并准备数据。
  测试环境尽量要和生产环境的结构保持一致,还有配置文件等也要保持一致,这样能保证性能测试的结果更加真实和接近生产环境。
  数据准备一定要充足,而且数据量要大于等于生产环境,这样能更真实的模拟生产环境。比如对一个select语句而言,10W的数据,和1000W的数据,查询时间肯定有差别。如果数据量太小就不能反映真实情况下性能了。(可以把线上的数据导入到测试环境,但是要注意把用户比较隐私的数据都替换掉)
  如果有可能的话,测试环境的数据要比生产环境多出20%,做一些性能上边的冗余,防止发生突然的性能尖峰。

 3、了解需求,找出测试点
  和产品、技术沟通需要做性能测试的业务;并了解相应的业务的性能指标,如页面的响应时间,TPS(事物处理)或者系统期望能承受多少并发等。
  4、设计性能能测试用例
  根据业务编写相应的性能测试用例。
  功能
  在线用户达到高峰时,用户可以正常发帖,保证200个以内用户可以同时发表帖子。
  目的
  测试系统200个以内的用户同时在线发帖。
  方法
  采用LoadRunner的录制工具录制一个邮件发送过程,然后对脚本进行优化,加上事物点,检查点等。过程中监视B端的响应,还有网络传输,web服务和数据库服务器的性能,并观察服务器相应服务的日志,检查MQ的状态,memcached服务器的状态和性能
  预期结果
  符合业务的预期,日志木有异常等(不详细列举)
  5、编写并优化脚本
  根据测试用例录制发帖的脚本,加入事物点、检查点、参数化,并回放,确保脚本没有问题,可以正常运行。
  6、设计性能测试场景
  设置一个渐进的场景10-30-60-100-150-200,这么做的目的防止一下子上去就是200个并发,出了问题,不知道系统最佳的并发是多少。
  (上边的渐进场景不一定合理,只做示意)
  7、启动监控,并开始跑性能测试场景
  设置场景完毕后,开始在服务器端启动监控,然后开始启动场景。
  8、监控场景执行,监控服务器的资源
  loadrunner可以搜集一些性能测试数据,事物的pass数,fail数,error数,都要做统计。
  监控服务器的资源,可以利用nmon,也可以是用linux自带的命令top,vmstat等。
  也要监控服务器的日志输出,看是否有异常出现。例如:查看mysql的慢日志,nginx的日志等。
  9、搜集结果数据,分析探讨
  最后对性能测试搜集的数据进行分析,找出性能测试的拐点。
  10、对系统进行优化,并重复7-9步,直至测试结束
  PS:性能测试不是一个人的事情,中间设计了,开发,产品,运维,QA,DBA,要大家共同协作,才能做好性能测试。
  限于水平有限,用疏漏之处,多多包涵。

posted @ 2014-06-25 11:25 顺其自然EVO 阅读(213) | 评论 (0)编辑 收藏

Tcpcopy常用的几种引流模式 3

  Tcpcopy 给用户提供了很多命令参数来修改引流的模式和设置,详细可以查阅手册。在这里把几种常见的引流方式做个归纳小结,以Tcpcopy传统架构使用命令举例。
  分布式引流
  用法:Tcpcopy可以通过-x参数实现将多台服务器的请求复制到同一台测试服务器上面去,-x参数常用于分布式引流的场合,可以从多节点进行引流复制。
  #./tcpcopy -x 2080- xxx.xx.x.xxx:9999
  #./tcpcopy -x 2080- xxx.xx.x.xxx:9999 -f 1
  #./tcpcopy -x 2080- xxx.xx.x.xxx 9999 -f 2
  适用场景:将线上一个集群的压力复制到测试服务器,适用于线上集群单节点压力小的情况,可以通过这种方式尽量覆盖线上所有的请求,这种方式常被用于容量规划之线上压测方式中的一种。
  分层引流
  对于一个复杂的线上系统,提供多种业务如图片、存储等,各种业务压力是不均衡的,如果在系统的最前端入口进行复制引流到测试环境,那么部分功能模块的压力将会很大,而部分功能模块的压力很小压不到上限,这时候分层引流就可以解决这样的问题,在系统架构每一层进行引流复制压测,尽量覆盖多的节点。以下是网易广告系统分层压测架构图。


 离线回放
  用法:离线回放模式需要再configure 的时候加上--enable-offline 参数,离线回放还需要安装pcap 库和pcap 开发库(需要用到pcap 库的头文件)另外运行的时候需要指定-i 参数。
  ./tcpcopy -x 110-xxx.xxx.xxx.148:110 -i ./online.pcap
  这里oline.pcap(利用类似于tcpdump 的工具来抓请求数据包,存放到pcap 格式的文件中去)文件作为数据源,把请求转发到测试服务器上。此外增加-a参数对请求数据包的访问进行加速
  ./tcpcopy -x 80-xxx.xxx.x.xx:8080 -a 2 -i online.pcap
  假设online.pcap 文件为在线请求数据包的抓包文件,时间间隔为60 分钟执行此命令后,离线回放加速了2 倍,只需要30 分钟离线回放就能完成,-a 参数设置不宜设置过大,越大丢请求的概率也越大。
  适用场景:由于离线方式依赖于抓包工具(如tcpdump),而抓包工具在压力比较大的场合一般丢包非常严重,而且还会严重影响在线IO,因此一般不推荐在高压情况下使用离线回放方式
  部分引流
  用法:Tcpcopy可以通过-r参数实现在线服务器应用的部分流量复制,参数范围是1~99,其它值都是全流量复制。-r 参数常用于测试服务器配置不如在线服务器的场合。
  #./tcpcopy -x 2080-xxx.xx.xx.xxx:9999 -r 20
  这里tcpcopy 复制在线服务器2080 端口应用的20%流量给测试服务器,这里的20%是根据session(这里session 是由客户端IP,客户端端口决定)来统计的。
  适用场景:部分引流主要适用于线上请求压力很多,而测试环境的处理能力较弱,这时候就只需复制部分线上的请求到测试环境,就可以压到测试环境的极限.
  放大引流
  用法:Tcpcopy可以通过-n参数对在线服务器应用的流量进行复制放到到测试服务器,如果你要进行多重复制,-n参数
  #./tcpcopy -x 2080-xxx.xx.x.xxx:9999 -n 3
  表示复制3 倍的在线服务器的80 端口应用请求流量到192.168.0.2 的8080 端口
  适用场景:放大引流主要用于线上压力较小时,想要通过无限构造压力通过成倍引流达到对测试服务器进行压力测试的目的
相关文章:
Tcpcopy两种架构原理详解 2

posted @ 2014-06-25 11:24 顺其自然EVO 阅读(1466) | 评论 (0)编辑 收藏

创建动态链接库Dll及测试用例

我们就从新建工程开始:
  (1)打开VS2010,文件->新建->项目,选择Win32项目
  (2)工程名叫做“Win32Dll”,在点击确定后弹出的对话框中选择Dll这一项,并勾选导入符号选项,点击完成
  这样一个创建Dll的工程就做好了,其实Dll的编写就是类的一种封装,格式完全可以按照C++中类的写法去完成,下面我改写了另一个老兄的例子:
  1.在Win32Dll.h中的类CWin32Dll 里添加:
class WIN32DLL_API CWin32Dll {
public:
CWin32Dll(void);
// TODO: 在此添加您的方法。
private:
int m_nVar;
std::string m_strVar;
public:
void set(int );
void printfValue();
void set_str(const std::string &);
void printf_str();
};
extern WIN32DLL_API int nWin32Dll;
//这里尤其要注意,当你想创建一个非成员函数时
WIN32DLL_API void printfValue(const int &);
WIN32DLL_API int fnWin32Dll(void);
  2.以上类中尤其要注意非成员函数的的声明,之后便是在Win32Dll.cpp中的函数实现
CWin32Dll::CWin32Dll()
{
return;
}
void CWin32Dll::set(int v)
{
m_nVar = v;
}
void CWin32Dll::printfValue()
{
std::cout << m_nVar << std::endl;
}
void CWin32Dll::set_str(const std::string &str)
{
m_strVar = str;
}
void CWin32Dll::printf_str()
{
std::cout << m_strVar << std::endl;
}
void printfValue(const int &v)
{
std::cout << v << std::endl;
}
  以上工作都做完后,进行编译链接,在工程Debug下就可以看到我们生成的.Dll文件和.lib文件

 3.在同一个解决方案里新建一个Win32控制台项目名叫TestWin32Dll
  在这里我们要用到我们在上个工程中生成的库文件
  如下是TestWin32Dll.cpp中的实现:
#include "stdafx.h"
#include "../Win32Dll/Win32Dll.h"
#pragma comment(lib,"D:/My Documents/Visual Studio 2010/Projects/Win32Dll/Debug/Win32Dll.lib")
int _tmain(int argc, _TCHAR* argv[])
{
int v = 12;
printfValue(v);
CWin32Dll obj;
obj.set(v);
obj.printfValue();
CWin32Dll obj2;
obj2.set_str("haha");
obj2.printf_str();
CWin32Dll obj3;
obj3.set_str("nono");
obj3.printf_str();
return 0;
}
  运行一下试试!

posted @ 2014-06-25 11:23 顺其自然EVO 阅读(214) | 评论 (0)编辑 收藏

淘宝Android自动化测试框架-TMTS

 2010年是淘宝无线突飞猛进开创无线新业务的一年。而从2011年初开始,淘宝技术质量部自动化测试组便致力于手机自动化框架的调研和开发工作。TMTS(Taobao Mobile Test System)框架,正是尝试从Android和IPhone入手,建立无线测试领域的自动化测试整体解决方案。经过前段时间的开发,及业务线试用,TMTS框架Android部分已经趋于稳定。而IPhone的自动化框架也已经开发完成,目前正在业务线试用阶段。
  本文重点介绍TMTS框架的Android部分,这部分目前已经开源。开源链接: http://code.taobao.org/project/view/565/
  在框架开发前,我们先是通过无线业务的同学,收集了明确的需求:
  支持对release版本的测试。即不需要为自动化测试专门打包。
  支持敏捷开发和持续集成。每天自动打包,自动运行测试用例,给出测试报告。
  支持内嵌WebView的自动化。淘宝有大量的应用有WebView的场景,需要自动化。
  在应用退出时调用killProcess杀掉自已进程,不应影响自动化测试的结果收集。
  之前也用过Robotium框架,但由于淘宝应用的特殊性,导致自动化能运行,但最后的结果收集不到,除非把killProcess代码注释掉再编译。
  针对上面的需求,TMTS使用Android SDK的Instrumentation机制作为自动化框架的基础,保证测试工程可以在不改写和重编译被测应用的基础上,与被测应用运行在同一个进程里,从而达到自动化测试的目的。针对淘宝无线的自动化测试场景,我们对原有Android控件进行了一次抽象,基类为TmtsView,这里定义了所有控件共有的操作,如click等。对于SDK中能编辑文字的控件如TextView,EditText统一抽象为TmtsTextView。对于容器类的View统一抽象为TmtsViewGroup,等等。简化了控件类型的选择,让测试脚本更简单易读。
  持续集成是自动化测试框架走向企业级应用的必经之路,只有持续集成、每日回归跑起来了,自动化才能有收益。我们对Athena框架进行了二次开发,加入了失败详情收集,失败截图上传,和运行异常处理的功能,并与hudson集成直接查看运行结果。同时我们还把每日构建也做起来,从开发的svn分支自动打包,自动测试,生成报表。这样每天只要查看运行结果就可以了,大幅度提高了效率。
  其它的很多功能,这里就不一一说明了。通过下面的表,列举TMTS,Robotium和Android Native Driver的特性与区别。

posted @ 2014-06-25 11:07 顺其自然EVO 阅读(284) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 96 97 98 99 100 101 102 103 104 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜