qileilove

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

Android JUnit test 进行自动化测试

  一. 被test的工程:
  新建一个android工程:D_session;它有一个activity:D_sessionActivity;package名:com.mysession
  二.测试工程:
  新建一个测试工程:D_sessionTest, 类型是android test project;
  1. menifest文件:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mysession.test"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.mysession" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<uses-library android:name="android.test.runner" />
</application>
</manifest>
  2. 一个base activity 来定义各种模拟测试者的动作和判断测试结果,各个测试类都继承该类:
package com.mysession.test;
import android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
import android.content.Intent;
import android.test.InstrumentationTestCase;
import android.test.TouchUtils;
import android.widget.Button;
import android.widget.TextView;
import com.mysession.D_sessionActivity;
public class SessionActivityTest extends InstrumentationTestCase {
private Instrumentation mInstrumentation;
private ActivityMonitor mSessionMonitor;
private Activity mCurrentActivity, mSessionActivity;
private String TextNotEqual = "text not equal.";
private static final String PackageName = "com.mysession";
@Override
protected void setUp() throws Exception {
// 初始化
super.setUp();
if (mInstrumentation == null) {
mInstrumentation = getInstrumentation();
}
mSessionActivity = null;
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
//释放资源
closeActivity(mSessionActivity);
mCurrentActivity = null;
}
private void closeActivity(Activity activity) {
if(activity != null){
activity.finish();
activity = null;
}
}
public void openSessionActivity() {
// 打开session activity
try {
setUp();
} catch (Exception e) {
e.printStackTrace();
}
mSessionMonitor = mInstrumentation.addMonitor(
D_sessionActivity.class.getName(), null, false);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName(PackageName, D_sessionActivity.class.getName());
mInstrumentation.startActivitySync(intent);
mSessionActivity = getInstrumentation().waitForMonitor(mSessionMonitor);
assertNotNull(mSessionActivity);
mCurrentActivity = mSessionActivity;
}
//判断text是否正确
public void assertTextEqual(int resId, String strText) {
TextView textView = (TextView) mCurrentActivity.findViewById(resId);
assertNotNull(textView);
assertEquals(TextNotEqual,
strText,
textView.getText().toString());
};
// 模拟按钮点击事件
public void clickButton(int resId){
Button button = (Button) mCurrentActivity.findViewById(resId);
assertNotNull(button);
TouchUtils.clickView(this, button);
}
}
 3. 各个测试类:
  测试类一:
package com.mysession.test.cases;
import com.mysession.R;
import com.mysession.test.SessionActivityTest;
public class MyCase1 extends SessionActivityTest {
public void testCase1() {
openSessionActivity();
assertTextEqual(R.id.etUrl,
"http://172.20.230.5/iportal/samples/jsapi/mobile.html");
}
public void testCase3() {
openSessionActivity();
clickButton(R.id.btnLoad);
clickButton(R.id.btnHistory);
}
}
  测试类二:
package com.mysession.test.cases;
import com.mysession.R;
import com.mysession.test.SessionActivityTest;
public class MyCase2 extends SessionActivityTest{
public void testCase2() {
openSessionActivity();
clickButton(R.id.btnLoad);
}
}
  三. 有些动作(如点击menu)需要通过包robotium-solo-1.8.0.jar来完成。
  所以要在Build Path->Configure Build Path…中导入:robotium-solo-1.8.0.jar
  程序中:
  private Solo solo;
  solo = new Solo(getInstrumentation(),getActivity);
  就可以使用solo了, 如:
  solo.clickOnMenuItem(text);
  solo.goBack();

posted @ 2014-08-13 09:52 顺其自然EVO 阅读(315) | 评论 (0)编辑 收藏

Web自动化测试原理

 目前有很多Web UI自动化测试框架,如WatiN,Selinimu,WebDriver等,这些框架都可以操作Web中的控件,模拟用户输入,点击等操作,实现Web自动化测试。其实这些工具的原理都一样,都是通过调用IE COM接口和HTMLDOM 对IE浏览器以及WEB测试对象的操作。 本文介绍脱离这些自动化测试框架,通过AutoIT直接使用IE COM接口结合HTML DOM对IE浏览器以及WEB对象进行自动化测试的方法。
  1.IE常用操作
  首先新建一个IE COM对象,配置IE窗口属性,模拟用户同时跳转至相应的页面同时进行相应操作。访问页面时,需要等待页面加载完成后再进行操作。这里我们可以使用IE COM的BUSY属性检查浏览器是否处于加载状态,再进行相应的操作。示例代码如下:
  2.利用DOM操作测试对象
  现在已经会使用IE COM组件来对IE浏览器进行自动化的操作,但是对于浏览器页面中的测试对象IE COM是无法对其进行操作的,这个时候就需要使用HTML DOM来对其进行操作。
  2.1 HTML DOM简介
  HTML DOM是HTML Document Object Model(文档对象模型)的缩写,它将网页中的各个元素都看作一个个对象,从而使网页中的元素也可以被计算机语言获取或者编辑。 常用DOM 属性如下:
  className.同一样式规则的元素用相同的类名。可以通过className快速过滤出一组类似的元素。
  document.用于指向包含当前元素的文档对象。
  id.当前元素的标识。如果文档中包含多个相同id的元素,则返回一个数组。
  innerHTML.用于指向当前元素的开始标记和结束标记之间的所有文本和HTML标签。
  innerText.用于指向当前元素的开始标记和结束标记之间的所有文本和HTML标签。
  offsetHeight, offsetWidth.元素的高度和宽度。
  offsetLeft, offsetTop.当前元素相同对于父亲元素的左边位置和顶部位置。
  outerHTML.当前元素的开始标记和结束标记之间的所有文本和HTML标签。
  outerText.当前元素的开始标记和结束标记之间的所有文本,但不包括HTML标签。
  parentElement.当前元素的父亲元素。
  sourceIndex.元素在document.all集合中的索引(index)。
  style.元素的样式表单属性。
  tagName.当前元素的标签名。
  title.在IE中,代表元素的tool tip文本
  常用DOM方法如下:
  click().模拟用户对当前元素的鼠标点击。
  contains(element).用于判断当前元素是否包含指定的元素。
  getAttribute(attributeName, caseSensitive).返回当前元素所包含的某个属性,参数attributeName为属性名、caseSensitive表示是否大小写敏感。
  setAttribute(attributeName, value, caseSenstive). 设置当前元素的属性。
  常用DOM 集合如下:
  All[].当前元素中包含的所有HTML元素的数组。
  children[].当前元素包含的子元素。
  2.2 种方法对比
  2.2.1getElementByID
  getElementByID( )方法可根据指定的id属性值得到对象。 首先需要分析页面,在Chome浏览器中选择相应的网页元素点击右键选择"审查元素"(或使用IE Develop Toolbar或者firebug等插件亦可),即可得到页面控件的ID等信息。  通过getElementByID方法获取百度搜索框及搜索按钮对象,并对其进行输入及点击操作,从而完成搜索操作。示例代码如下:
  2.2.2getElementsByName
  getElementsByName( )方法可返回带有指定名称的对象的集合。
  同样获取网页元素name后,即可通过getElementsByName方法获取定位对象,并对其进行操作(与getElementByID返回的单个对象不同,getElementsByName返回的是一个元素的集合,需要通过遍历对象才能对其进行操作):
  2.2.3getElementsByTagName
  getElementsByTagName( )方法通过查找整个HTML文档中的任何HTML元素,传回指定名称的元素集合。 因此也可使用getElementsByTagName获取TAG名,通过得到相同类型的元素及在遍历中进行判断控件类型并进行操作:
  2.3 利用FORM名来获取对象元素
  使用FORM名来获取对象元素会大大简化我们的脚本。首先查看百度的搜索框对应的FORM名,得到FORM名为f: 
通过如下简单的脚本,同样可以达到相同的效果:
  2.4 访问Web页面的Script脚本变量
  通过DOM还可以直接访问Web页面中的JavaScript或者VBScript中的变量。首先打开百度的源文件:
  可以看到在百度源文件的JavaScript脚本中定义了一个变量为k,并且赋值为d.f.wd(实际上就是百度搜索框对象)。那么可以直接使用parentWindow来访问Web页面Script中的变量k,对百度搜索框进行自动测试:
  3 总结
  本文主要介绍了利用IE的COM以及HTML DOM来自动化IE浏览器,以及对浏览器的一些控件对象进行自动化的操作,包括IE浏览器常用操作、利用DOM操作测试对象、利用FORM名来获取对象元素、访问Web页面的Script脚本变量等。 直接操作IE COM来实现Web自动化,不仅有助于有助于理解Web页面自动化测试框架的运行原理,还能脱离这些自动化测试框架自己快速建立一个轻量型的自动化测试程序,从而真正的提高测试效率。
原文链接:http://lovesoo.org/web-automation-testing-principle.html

posted @ 2014-08-13 09:49 顺其自然EVO 阅读(879) | 评论 (0)编辑 收藏

Junit单元测试小应用

  测试是一个很重要的问题,我觉得:一个程序员行不行,关键看他会不会调试。程序的测试都是从小范围入手然后向四面八方入手,一点点的向外扩展,直至最后程序整体运行良好。这只是在下的一点愚见。以前进行调试时总是在程序中写个main方法,然后进行测试,以前学过一个Junit单元测试,没想起来用,今天看见老师的代码中有这个单元测试,所以下来了看了看以前的代码并上网查了查有关Junit的东西,在此简单的说一下。以MyElipse 8.5 进行说明。
  1.新建一个project,然后右击选择properties-----Java Build Path-----Libraries---AddLibrary---Junit,将Junit插件添加到该项目中。
  2.在project中建立一个JDemo.java 和 Test.java,JDemo中由一个简单的方法add(),Test要继承TestCase,代码如下:
JDemo.java
package com.bx.testjunit;
public class JDemo {
int a;
int b;
int result;
public int add(int a,int b){
result = a + b;
return result;
}
}
Test.java
package com.bx.testjunit;
import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
public class Test extends TestCase{
@Before
public void setUp() throws Exception {
System.out.println("Test :setUp");
}
@After
public void tearDown() throws Exception {
System.out.println("Test :tearDown");
}
public void test(){
JDemo a = new JDemo();
assertEquals(6,a.add(3, 3));
}
}
  3.运行,右击Junit Test,在控制台上会出来一个Junit选项卡,如果出现绿颜色的bar则说明程序正确,如果是红颜色的bar则说明程序错误,需进行检错。
  上面的程序用的是Junit3,必须继承TestCase
  下面看一个Junit4的例子
package com.bx.service;
import org.junit.Test;
public class HelloWorld {
@Test
public void test(){
System.out.println("HelloWord :test");
}
}
  Junit4不需要继承TestCase,只需使用@Test标注的expected属性。

posted @ 2014-08-13 09:47 顺其自然EVO 阅读(200) | 评论 (0)编辑 收藏

如何写功能测试报告

1、项目进度
  1.1测试执行阶段
  写清楚当前是在冒烟测试功能测试执行阶段,还是回归测试阶段
  写清楚当前阶段预计在什么时候结束(在可控的情况下,如果不可控或者不可预测,说明风险在哪里)
  写清楚当前测试了哪个模块,还有哪些模块没有测试(一般都是先测试优先级高的模块)
  写清楚下个星期的测试计划是什么
  2、测试情况
  2.1 再介绍一下本周的测试模块
  2.2 写清楚当前模块的质量情况:open了多少bug,fix了多少,close了多少。bug的趋势是什么(后期应当收敛,在前期如果未收敛,解释未收敛的原因)
  2.3 本周遇到的问题是什么(风险是什么)
  3、贴图
  3.1 相关图片,有需要解释的进行解释(如reopen的bug,高级别的bug)

posted @ 2014-08-13 09:46 顺其自然EVO 阅读(249) | 评论 (0)编辑 收藏

Java 接口和抽象类区别

1.概述

一个软件设计的好坏,我想很大程度上取决于它的整体架构,而这个整体架构其实就是你对整个宏观商业业务的抽象框架,当代表业务逻辑的高层抽象层结构 合理时,你底层的具体实现需要考虑的就仅仅是一些算法和一些具体的业务实现了。当你需要再开发另一个相近的项目时,你以前的抽象层说不定还可以再次利用 。面对对象的设计,复用的重点其实应该是抽象层的复用,而不是具体某一个代码块的复用

说到了抽象,我就不能不提到曾让我头痛的Java接口和Java抽象类了,这也是本文我想说的重点。

既然面向对象设计的重点在于抽象,那Java接口和Java抽象类就有它存在的必然性了。

Java接口(interface)和Java抽象类(abstract class)代表的就是抽象类型,就是我们需要提出的抽象层的具体表现。OOP面向对象的编程,如果要提高程序的复用率,增加程序 的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程,正确地使用接口、抽象类这些有用的抽象类型作为你结构层次上的顶层。

Java接口和Java抽象类有太多相似的地方,又有太多特别的地方,究竟在什么地方,才是它们的最佳位置呢?把它们比较一下,你就可以发现了。

  1. Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以(就是interface中只能定义方法,而不能有方法的实现,而在abstract class中则可以既有方法的具体实现,又有没有具体实现的抽象方法),这大概就是Java抽象类唯一的优点吧,但这个优点非常有用。如果向一个抽象类里加入一个新的具体方法时,那么它所有的子类都一下子都得到了这个新方法,而Java接口做不到这一点,如果向一个Java接口里加入一个 新方法,所有实现这个接口的类就无法成功通过编译了,因为你必须让每一个类都再实现这个方法才行,这显然是Java接口的缺点这个在我的另外一篇博客mapreduce 新旧API 区别中有提到类似的问题,在新的mapreduce api中更倾向于使用抽象类,而不是接口,因为这更容易扩展。原因就是上面划线部分所说的。
  2. 一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现处在抽象类所定义出的继承的等级结构中,而由于Java语言的单继承性,所以抽象类作为类型定义工具的效能大打折扣。在这一点上,Java接口的优势就出来了,任何一个实现了一个Java接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个Java接口,从而这个类就有了多种类型。(使用抽象类,那么继承这个抽象类的子类类型就比较单一,因为子类只能单继承抽象类;而子类能够同时实现多个接口,因为类型就比较多。接口和抽象类都可以定义对象,但是只能用他们的具体实现类来进行实例化。)
  3. 从第2点不难看出,Java接口是定义混合类型的理想工具,混合类表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为。
  4. 结合1、2点中抽象类和Java接口的各自优势,具精典的设计模式就出来了:声明类型的工作仍然由Java接口承担,但是同时给出一个Java 抽象类,且实现了这个接口,而其他同属于这个抽象类型的具体类可以选择实现这个Java接口,也可以选择继承这个抽象类,也就是说在层次结构中,Java 接口在最上面,然后紧跟着抽象类,这下两个的最大优点都能发挥到极至了。这个模式就是“缺省适配模式”。在Java语言API中用了这种模式,而且全都遵循一定的命名规范:Abstract +接口名。(A extends AbstractB implements interfaceC,那么A即可以选择实现(@Override)接口interfaceC中的方法,也可以选择不实现;A即可以选择实现(@Override)抽象类AbstractB中的方法,也可以选择不实现)

Java接口和Java抽象类的存在就是为了用于具体类的实现和继承的,如果你准备写一个具体类去继承另一个具体类的话,那你的设计就有很大问题了。Java抽象类就是为了继承而存在的,它的抽象方法就是为了强制子类必须去实现的。

使用Java接口和抽象Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明,以及数据类型的转换等。而不要用具体Java类进行变量的类型声明、参数是类型声明、方法的返还类型说明,以及数据类型的转换等。

2.实例

下面给出一个具体的接口Action,代码如下所示:

  1. package org.springframework.webflow.execution;  
  2. public interface Action {  
  3.     public Event execute(RequestContext context) throws Exception;  
  4. }  
在这个接口中,定义了一个没有具体实现的方法,方法名叫做execute(),返回类型是Event。如前面第一条所述,接口中的方法都是没有实现的。这些方法的具体实现是在实现(implements)这个接口的类中给出的。

再来看一个实现Action接口的抽象类AbstractAction,代码如下。

  1. package org.springframework.webflow.action;  
  2.   
  3. import org.apache.commons.logging.Log;  
  4. import org.apache.commons.logging.LogFactory;  
  5. import org.springframework.beans.factory.BeanInitializationException;  
  6. import org.springframework.beans.factory.InitializingBean;  
  7. import org.springframework.util.ClassUtils;  
  8. import org.springframework.webflow.core.collection.AttributeMap;  
  9. import org.springframework.webflow.execution.Action;  
  10. import org.springframework.webflow.execution.Event;  
  11. import org.springframework.webflow.execution.RequestContext;  
  12.   
  13. public abstract class AbstractAction implements Action, InitializingBean {  
  14.   
  15.     protected final Log logger = LogFactory.getLog(getClass());  
  16.   
  17.     public EventFactorySupport getEventFactorySupport() {  
  18.         return new EventFactorySupport();  
  19.     }  
  20.   
  21.     public void afterPropertiesSet() throws Exception {  
  22.         try {  
  23.             initAction();  
  24.         } catch (Exception ex) {  
  25.             throw new BeanInitializationException("Initialization of this Action failed: " + ex.getMessage(), ex);  
  26.         }  
  27.     }  
  28.   
  29.     protected void initAction() throws Exception {  
  30.     }  
  31.   
  32.     protected Event success() {  
  33.         return getEventFactorySupport().success(this);  
  34.     }  
  35.   
  36.     protected Event success(Object result) {  
  37.         return getEventFactorySupport().success(this, result);  
  38.     }  
  39.   
  40.     protected Event error() {  
  41.         return getEventFactorySupport().error(this);  
  42.     }  
  43.   
  44.     protected Event error(Exception e) {  
  45.         return getEventFactorySupport().error(this, e);  
  46.     }  
  47.   
  48.     protected Event yes() {  
  49.         return getEventFactorySupport().yes(this);  
  50.     }  
  51.   
  52.     protected Event no() {  
  53.         return getEventFactorySupport().no(this);  
  54.     }  
  55.   
  56.     protected Event result(boolean booleanResult) {  
  57.         return getEventFactorySupport().event(this, booleanResult);  
  58.     }  
  59.   
  60.     protected Event result(String eventId) {  
  61.         return getEventFactorySupport().event(this, eventId);  
  62.     }  
  63.   
  64.     protected Event result(String eventId, AttributeMap resultAttributes) {  
  65.         return getEventFactorySupport().event(this, eventId, resultAttributes);  
  66.     }  
  67.   
  68.     protected Event result(String eventId, String resultAttributeName, Object resultAttributeValue) {  
  69.         return getEventFactorySupport().event(this, eventId, resultAttributeName, resultAttributeValue);  
  70.     }  
  71.   
  72.     public final Event execute(RequestContext context) throws Exception {  
  73.         Event result = doPreExecute(context);  
  74.         if (result == null) {  
  75.             result = doExecute(context);  
  76.             doPostExecute(context);  
  77.         } else {  
  78.             if (logger.isInfoEnabled()) {  
  79.                 logger.info("Action execution disallowed; pre-execution result is '" + result.getId() + "'");  
  80.             }  
  81.         }  
  82.         return result;  
  83.     }  
  84.   
  85.     protected String getActionNameForLogging() {  
  86.         return ClassUtils.getShortName(getClass());  
  87.     }  
  88.   
  89.     protected Event doPreExecute(RequestContext context) throws Exception {  
  90.         return null;  
  91.     }  
  92.   
  93.     //抽象方法  
  94.     protected abstract Event doExecute(RequestContext context) throws Exception;  
  95.   
  96.     protected void doPostExecute(RequestContext context) throws Exception {  
  97.     }  
  98. }  
在抽象类AbstractAction中,既有具体实现的方法,又有没有具体实现的抽象方法

  1. //抽象方法  
  2. protected abstract Event doExecute(RequestContext context) throws Exception;  
需要注意的是在抽象类中,如果方法没有具体实现(就是方法后面没有{}),那么必须加上abstract来声明这个方法,而接口中不需要使用abstract来声明(抽象类之所以被称为抽象类,就是因为它包含有抽象方法。含有抽象方法的类叫做抽象类)

posted @ 2014-08-12 09:48 顺其自然EVO 阅读(234) | 评论 (0)编辑 收藏

数据库锁和数据库隔离级别

最近突然发现忘了数据库锁和数据库隔离级别,时常弄混它们之间的关系。为此特此写下此博客,以方便自己复习,同时也可以帮助博友。
  数据库锁
  数据库锁就是事务T在对某个数据对象(例如表、记录等)操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象。
  数据库锁是实现并发控制的重要技术,但是“锁”会带来系统额外的开销。所以需要注意选择封锁粒度时必须同时考虑开销和并发度两个因素,进行权衡,以求得最优的效果。
  锁的类型主要有两种类型排它锁(也叫独占锁)和共享锁,当然还有很多教程增加了一种--更新锁。
  共享(S)锁:多个事务可封锁一个共享页;任何事务都不能修改该页; 通常是该页被读取完毕,S锁立即被释放。在执行select语句的时候需要给操作对象(表或者一些记录)加上共享锁,但加锁之前需要检查是否有排他锁,如果没有,则可以加共享锁(一个对象上可以加n个共享锁),否则不行。共享锁通常在执行完select语句之后被释放,当然也有可能是在事务结束(包括正常结束和异常结束)的时候被释放,主要取决与数据库所设置的事务隔离级别。
  排它(X)锁:仅允许一个事务封锁此页;其他任何事务必须等到X锁被释放才能对该页进行访问;X锁一直到事务结束才能被释放。执行insert、update、delete语句的时候需要给操作的对象加排他锁(我感觉在执行insert的时候应该是在表级加排他锁),在加排他锁之前必须确认该对象上没有其他任何锁,一旦加上排他锁之后,就不能再给这个对象加其他任何锁。排他锁的释放通常是在事务结束的时候(当然也有例外,就是在数据库事务隔离级别被设置成Read Uncommitted(读未提交数据)的时候,这种情况下排他锁会在执行完更新操作之后就释放,而不是在事务结束的时候)。
  更新(U)锁:用来预定要对此页施加X锁,它允许其他事务读,但不允许再施加U锁或X锁;当被读取的页将要被更新时,则升级为X锁;U锁一直到事务结束时才能被释放。数据库是支持在一个事务中进行自动锁升级的,例如,在某个事务中先执行select语句,后执行update语句,这两条语句操作了同一个对象,并且假定共享锁是在事务结束的时候被释放的。如果数据库不支持自动锁升级,那么当update语句请求排他锁的时候将不能成功。因为之前select语句的共享锁没有被释放,那么事务就进入了无限等待,即死锁。有了自动锁升级,在执行update语句的时候就可以将之前加的共享锁升级为排他锁,但有个前提,就是这个共享锁必须是本事务自己加的,而且在操作对象上没有在加其他任何锁,否则共享锁是不能被升级为排他锁的,必须等待其他锁的释放。
  因为通常在执行更新操作的时候要先查询,也就是我们通常会在update语句和delete语句中加where子句。那么,有的数据库系统可能会在执行查询的时候先给操作对象加共享锁,然后在更新的时候加排他锁,但这么做会有问题,也就是如果两个事务同时要更新一个对象,都先给这个对象加了共享锁,当要更新的时候,都请求升级锁,但由于这个对象上存在对方事务加的共享锁。。所以无法升级。这样两个事务就在等待对方释放共享锁,进入死锁状态。更新锁就是为了解决这个问题,即在执行查询操作的时候加的不是共享锁而是更新锁(一个对象上只能有一个更新锁和n个共享锁),当要更新的时候,再将更新锁升级为排他锁,升级前提是这个对象上只有本事务加的更新锁,没有其他任何锁了。其实,,我想,如果在执行查询的时候就给事务加排他锁不也能解决死锁问题吗,但这样似乎会减弱系统的并发性能。
  数据库的事务隔离级别
  在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。
在没有数据库的事务隔离级别时会出现如下问题:
  更新丢失
  两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。这是因为系统没有执行任何的锁操作,因此并发事务并没有被隔离开来。
  脏读
  一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。
  不可重复读
  不可重复读(Non-repeatable Reads):一个事务对同一行数据重复读取两次,但是却得到了不同的结果。
  包括以下情况:
  (1) 事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读该数据时得到与前一次不同的值。
  (2) 幻读(Phantom Reads):事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。
  为了避免上面出现的几种情况,在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同。
  未授权读取
  也称为读未提交(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。
  授权读取
  也称为读提交(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
  可重复读取(Repeatable Read)
  可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻影数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
  序列化(Serializable)
  序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
  隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、虚读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

posted @ 2014-08-12 09:36 顺其自然EVO 阅读(222) | 评论 (0)编辑 收藏

iOS-三步快速集成社交化分享工具ShareSDK

 1.前言
  作为现在App里必不可少的用户分享需要,社交化分享显然是我们开发app里较为常用的。
  最近因为公司App有社交化分享的需要,就特此研究了会,拿出来与大家分享。
  想要集成社交会分享,我们可以使用
  ShareSDK - 优点功能丰富,缺点体积较大
  百度分享SDK - 缺点功能相对ShareSDK较少,优点体积较小
  这是现在较为常用的两种社交化分享工具。
  使用哪一种,就看个人的app的需要来决定了。
  今天我主要说的是ShareSDK的简单集成和使用。
  2.集成前的准备工作
  2.1. 拿自己的Appkey 去下载ShareSDK
  下载地址:http://sharesdk.cn/Download
  2.2. 申请分享工具的Appkey
  例如: 新浪微博、腾讯微博、豆瓣应用、人人网、QQ空间
  去各大社交网站的开发者平台,进行注册申请即可。
  获取如下:
  //新浪微博:
  //App Key:2258477553
  //App Secret:1e2f275afc375109e456f550fb3918e8
  //腾讯微博:
  //App key:2620460989
  //App secret:58c55f572d5ae35e0c355f4c0ee11283
  3.集成ShareSDK
  3.1.注册使用ShareSDK
  - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  {
  //注册ShareSDK
  [ShareSDK registerApp:@"1983bf0916db”];
  return YES;
  }
  3.2.添加要集成的分享平台
  注意: 新浪微博需要提供回调地址才行
  回调地址去新浪开发者平台获取
  如图:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//注册ShareSDK
[ShareSDK registerApp:@"1983bf0916db”];
//添加新浪微博应用
[ShareSDK connectSinaWeiboWithAppKey:@"2620460989"
appSecret:@"58c55f572d5ae35e0c355f4c0ee11283"
redirectUri:@"http://weibo.cn/ext/share?ru=http%3A%2F%2F16kxs.com%2Fwap%2FBook%2FShow.aspx%3Fid%3D7983%26lmid%3D0%26uid%3D0%26ups%3D0&rt=%E9%83%BD%E5%B8%82%E7%89%A7%E9%AC%BC%E4%BA%BA&st=1301645308&appkey=2620460989”];
//添加腾讯微博应用
[ShareSDK connectTencentWeiboWithAppKey:@"801307650"
appSecret:@"ae36f4ee3946e1cbb98d6965b0b2ff5c"
redirectUri:@"http://www.sharesdk.cn"];
//添加豆瓣应用
[ShareSDK connectDoubanWithAppKey:@"07d08fbfc1210e931771af3f43632bb9"
appSecret:@"e32896161e72be91"
redirectUri:@"http://dev.kumoway.com/braininference/infos.php"];
//添加人人网应用
[ShareSDK connectRenRenWithAppKey:@"fc5b8aed373c4c27a05b712acba0f8c3"
appSecret:@"f29df781abdd4f49beca5a2194676ca4"];
//添加Facebook应用
[ShareSDK connectFacebookWithAppKey:@"107704292745179"
appSecret:@"38053202e1a5fe26c80c753071f0b573"];
}
  3.3.弹出分享View
  a.初始化默认分享内容
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"123"  ofType:@"png"];
//构建优秀的SDK
//构造分享内容
id<ISSContent> publishContent = [ShareSDK content:@"iOS社交化分享测试内容。"
defaultContent:@"默认分享内容,没内容时显示"
image:[ShareSDK imageWithPath:imagePath]
title:@"ShareSDK"
url:@"http://www.sharesdk.cn"
description:@"这是一条测试信息"
mediaType:SSPublishContentMediaTypeNews];
  b.弹出分享View
[ShareSDK showShareActionSheet:nil
shareList:nil
content:publishContent
statusBarTips:YES
authOptions:nil
shareOptions: nil
result:^(ShareType type, SSResponseState state, id<ISSPlatformShareInfo> statusInfo, id<ICMErrorInfo> error, BOOL end) {
if (state == SSResponseStateSuccess)
{
NSLog(@"分享成功");
}
else if (state == SSResponseStateFail)
{
NSLog(@"分享失败,错误码:%d,错误描述:%@", [error errorCode], [error errorDescription]);
}
}];
  效果图:

posted @ 2014-08-12 09:36 顺其自然EVO 阅读(1341) | 评论 (0)编辑 收藏

Java变量初始化的时机

  对于JAVA中变量的初始化是一个很基础的问题,其中的一些问题也是易被学习者所忽略。当在编写代码的时候碰到时,常被这些问题引发的错误,感觉莫名其妙。而且现在许多大公司的面试题,对于这方面的考查也是屡试不爽。以下是对java变量初始化的时机的分析。
  【java变量执行初始化的步骤】
  java是一门强类型语言,因此java语言规定每个变量必须先声明,然后才能使用,声明变量时必须指定该变量的数据类型。首先看下面这条语句的执行过程:
  int a = 5;
  实际上面这条语句会被拆分成两个过程执行:
  (1)int a ;//创建java对象时根据该语句为变量分配内存空间;
  (2)a = 5;//赋值操作会最终被提取到构造器中执行初始化操作。
  实际上在java中,在使用new操作符创建一个类的实例对象的时候,开始分配空间并将成员变量初始化为默认的数值,在这里并不是指将变量初始化为在变量定义处的初始值,对于基本类型变量,默认值空值是0或false,对于引用类型变量,默认空值为null。这一切都是在构造函数执行之前,变量的真正初始化是在构造函数中执行。
  【java中变量初始化的时机】
  1、程序可以在3个地方对实例变量进行初始化:
  (1)定义实例变量的时候指定初始值;
  (2)非静态初始化代码块中对实例变量指定初值;
  (3)构造器中对实例变量指定初值。
  虽然程序在3个地方都可对实例变量指定初始值,但(1)、(2)处的赋值操作最终会被提取到构造器中执行。且(1)、(2)的执行顺序与他们在源程序中出现的顺序相同。可以通过JDK的javap工具来看程序的执行过程:
  2、java中类变量初始化的时机:
  (1)定义类变量的时候指定初始值;
  (2)静态初始化代码块中对类变量指定初值。
  这里类变量初始化的时机为两处,而没有在构造器中这一说。这也很容易理解,因为类变量是类加载的时候执行的初始化,且只执行一次,而调用构造器是对象实例化执行的,每实例化一次对象,执行一次。

posted @ 2014-08-12 09:34 顺其自然EVO 阅读(201) | 评论 (0)编辑 收藏

第一个公司的iOS项目总结

 第一个正式的universal项目差不多快要结束,总结一下,分享给大家。因为可能我的比较具有代表性,如何从压根不懂开始做起。(分享的另外一个目的也是希望大家提提建议,毕竟只有互相交流中才能更快成长)
  -----------------------------------------------
  做项目前:
  零面向对象实际项目经验,更不用说透彻理解design pattern
  零iOS实际项目经验
  只懂一点点的C和汇编代码,其它如java、ruby、php、HTML5一点不沾边,可以说是不属于互联网的业余玩家
  项目的情况:
  做项目过程中,客户需求变化极其频繁和巨大,对代码结构的robust是一大挑战。虽然本人特别讨厌需求变动,但是在外,身不由己
  Universal项目,即是iPhone + iPad 的一个项目
  基本上这个项目涉及到了iOS的方方面面,麻雀虽小,但是五脏俱全
  关于程序结构设计
  尝试用面向对象的方式去设计结构,但设计的时候流于形式,根据现有的一些best practice依葫芦画瓢,但实际上只有实践了才知道,比如:
  1. 属性: 什么时候用和为什么用属性、如何保持属性私有、self.的使用,属性的内存释放;
  2. 成员变量和属性的区别
  3. 方法:什么时候用类方法和对象方法
  4. 好的设计真的是“增之一分则太长,减之一分则太短”;好的设计关系到以后重构的方便性
  5. 解耦设计:对象之间如何通讯,如何传值,如何回传,如何用好notification、delegate、KVO;如何保持对象的纯洁(不受玷污)
  6. MVC中的M和C分离,一直觉得自己做的项目是小项目,而且一直认为过于注重结构,会增加代码量,但是实际上项目不分大小,好的设计:
  能随时应对客户的需求变化
  能自己看得懂自己写的代码(改的多了,都看不懂自己的代码了,这是最悲催)
  回归测试,一旦客户需求改变,乱糟糟的代码更加乱,这样回归基本上是需要全部。好的设计可以把客户需求改变带来的回归测试降低到最低
  关于面向对象设计
  之前从没有面向对象设计的经验,所以第一次从这种角度去解决问题。“实践出真理”,无论你平时看多少书,如果没有实践过,真的是无法体会面向对象设计的:
  一切从面向对象出发设计:类、对象、(私有)方法、(私有)属性
  所谓面向对象,就是根据现实世界中客观存在的事物(即对象)出发来构造软件系统
  只有真正从面向对象去设计,几个月甚至几年后,你才能复盘你的代码。以前一直觉得代码复盘如同围棋复盘绝对是天才才有的本领,现在才明白,其实关键是:你要清楚的知道你的代码用在了哪里,为什么用
  从面向对象出发,不要觉得一个功能很简单一个方法就搞定,尽量用面向对象去考虑。这是做项目过程中犯的最大的错误
  关于ARC
  我是项目做了1个月后,才决定把项目从MRC转到ARC,现在回头看看,当初真实明智,因为在第一个月,内存管理上的问题和处理让我很头疼也很花时间。关于ARC
  没有想象中的会比MRC性能差,ARC不是JAVA的垃圾回收,性能其实与MRC基本一致
  ARC中没有明确的release操作,这时更需要注意内存管理,比如在一个Controller中使用Gyro sensor的时候,这种操作是绝对不能赋值给局部变量的:[[CMMotionManager alloc]init]
  虽然ARC似乎能为你做很多事,但是有些事情自己解决还是自己解决,比如当不需要用Gyro sensor时,_motionManager = nil(此时如果不设置,则startDeviceMotionUpdatesToQueue中的更新会一直进行);
  总之,对于ARC,难得糊涂中要“时刻保持觉醒”
  关于Perfomrance设计
  Coding真的是一点都来不得马虎,以前一直觉得iOS性能强大,无须担心性能,但是项目做下来,一大痛苦之处就是性能不够:
  应用程序、UIViewController和UIView的生命周期的认识如果不十分清楚,就很容易造成性能瓶颈
  大量的UIView插入移除操作会导致性能问题
  UITableView和UIScrollView导致滑动不顺畅的best practice
  关于知识点
  成为一名优秀Programmer需要丰富的经验和知识面,但是知识永远是学习不完的,所以要抓核心和基本,个人觉得以下几个知识点是iOS开发必须的。至于有些比如CoreText、CoreImage等,其实等到需要用时再去学习也来得及。
  内存管理,MRC和ARC
  多线程,iOS下有多种多线程实现方式,什么都应该了解一下,但是除了dispatch需要精通,其它只需要看懂 (dispatch效率最高,使用最方便)
  数据库,无论是Core Data,FMDB还是基本的Sqlite,万事不离其中,掌握Sqlite和SQL基本语法是必须的
  UIViewController、UITableViewController 和应用程序的生命周期
  看似简单但是很有深度的View之间的转场处理,因为涉及到大量生命周期,如presentModalViewController, presentViewController, pushViewController, addSubview, removeFromSuperview, self.view....
  网络处理相关的,如何请求JSON数据,如何HTTP GET和POST
  旋转处理,特别是iOS4、iOS5、iOS6的不同处理
  Debug的能力
  基本的设计模式:MVC、delegate、notification、target-action
  面向对象的核心思想,例如:不要以用户无法使用或不感兴趣的东西扰乱类的公有接口、类之间应该零耦合、把不相关的信息放在另一个类中
  不重复造轮子
  这个也不例外,iOS下的开源framework都太多了,基本上你需要的都能在Github或者Stackoverflow上找得到,所以平时:
  不要做井底之蛙,平时多了解开源的框架
  框架适合就行,就像争论AFNetwork和ASIHttpNetwork更棒没有意义的。写程序的有两类人,一类人追求技术极致,一类人技术只是实现产品的一种手段,我就是后面这个
  关于开源框架的学习
  这世界好的开源框架太多了,给我10年都看不完,所以需要选择,就像读书不在于都多,而在于读精,个人推荐如下。
  Three20 (其实我是不推荐的,因为它过时了,但是因为淘宝客户端用到)
  AFNetwork
  MBProgressHUD
  SDWebImage
  关于Continuous Improvement
  Six sigma中提到了持续改进,我们的能力提高也是这样。通过读好的开源框架是最好的进步方式。如何读开源框架,我们读开源框架的目的:
  其中的花式写法我们只是了解,不是我们的目的
  了解作者写框架的思路
  对比自己现有的,求改进
 关于设计模式
  做项目前,把GOF的23种设计模式都看了一遍,项目做下了,体会到:
  单看设计模式的书,纯粹是无用;
  设计模式的核心在于平时的有意无意的使用,因为它本身来源于实际;
  能熟背23种设计模式固然是件好事,但是不能也不见得是坏事(反正我是记不住的)
  欲速则不达
  代码之间往往只查一两个字符,但性能和结局多半千差万别,因为项目紧,压力大,又是第一个项目,所以写代码的时候,追求:"meet requirement,先满足功能,再考虑代码结构",但是实际:
  需求无论大小,代码结构设计是必须的而且是第一位的,因为这关系到未来的改动,未来自己能否看懂;
  欲速则不达,真是一个真理
  关于Best Practice的重要
  iOS已经很成熟了,基本上,所有问题都能找到答案,所有的需求都有现成的framework,或者只需要稍许改改。但是也正因为“万能的internet”,所以很多答案或者很多framework都是有问题的,所以适时总结很重要:
  把常用的代码或者容易错的代码写到Xcode的snippet中
  要有自己的library,不是自己摆酷,而是知识需要积累,有些开发中经常会遇到的
  用好的framework。不流行的框架要注意是否用了私有方法(苹果 will reject it)
  best practice,比如如何自定义TableCell,如何自定义Navigation bar
  不玩花的,不玩偏门的,写代码就是规规矩矩,一切按照苹果的best practice写
  面向对象的思想有很多概要,平时要时刻提醒自己
  关于HTML5
  iOS原生与HTML5 WEB APP天生就是一对敌人,做HTML5的可以不懂iOS开发,但是做iOS开发必须懂点HTML5:
  iOS应用中一些“高度变化”或“性能要求不高”或“上线紧迫”的地方会用到UIWebView
  iOS原生与UIWebView的之间交互其实也可以很棒,甚至JSP交互
  HTML5是“可能”的未来,世界都在谈论
  HTML5看似只有一个知识点,但是其实要求比iOS原生开都高:一个典型的移动HTML5页面 = JSP + HTML + CSS + JQuery + backbone.js。或者学习PhoneGap也是不错的注意。
  关于未来:
  如何让自己在最短的时间内成为优秀,这是每天都在思考的,因为对比别人_大学+工作下来的多年工作经验,我是不惧任何优势的,但是既然入行,就必须做优秀。所以选择值得做的事尤其重要:
  看书没用,实践和Coding是提高能力的唯一途径;
  做实际项目比自己玩玩靠谱十万倍
  压力下工作成长更快,所以不断挑战自己,人的潜力是无限的
  番茄工作法则比较适合我(每次集中做半个小时)

posted @ 2014-08-12 09:33 顺其自然EVO 阅读(2933) | 评论 (1)编辑 收藏

目前流行的缺陷管理工具

 缺陷管理工具:
  1. Bugzilla
  2. Bugfree
  3. TestDirector (Quality Center)
  4. ClearQuest
  5. JIRA
  6. Mantis
  7. Bugzero
  8. BugTracker
  9. URTracker
  10.KisTracker
  11.TestLink
  12、JTrac
  13、BugNet
  14、BugOnline
  15、eTraxis
  一、Bugzilla(免费,跨平台)
  Bugzilla是一个Bug追踪系统设计用来帮助你管理软件开发
  Bugzilla是一开源Bug Tracking System,是专门为Unix定制开发的。但是在windows平台下依然可以成功安装使用.
  Testopia是一款和Bugzilla集成到一起的test case management系统.
  它的强大功能表现在以下几个方面:
  1. 强大的检索功能
  2. 用户可配置的通过Email公布Bug变更
  3. 历史变更记录
  4. 通过跟踪和描述处理Bug
  5. 附件管理
  6. 完备的产品分类方案和细致的安全策略
  7. 安全的审核机制
  8. 强大的后端数据库支持
  9. Web,Xml,Email和控制界面
  10. 友好的网络用户界面
  11. 丰富多样的配置设定
  12. 版本间向下兼容
  二、BugFree(免费)
  BugFree是借鉴微软的研发流程和Bug管理理念,使用PHP+MySQL独立写出的一个Bug管理系统。简单实用、免费并且开放源代码(遵循GNU GPL)。
  三、Quality Center(商业,前身Mercury TestDirector ,跨平台)
  HP Quality Center; 提供了基于 Web 的系统,可在广泛的应用环境下自动执行软件质量测试和管理。仪表盘技术使您可以了解验证功能和将业务流程自动化,并确定生产中阻碍业务成果的瓶颈。HP Quality Center 使 IT 团队能够在开发流程完成前就参与应用程序测试。这样将缩短发布时间表,同时确保最高水平的质量。
  企业级的软件质量解决方案。
  四、IBM Rational ClearQuest (商业,跨平台)
  IBM Rational ClearQuest 是一款强大的软件开发测试工具。集成并自动化软件及系统开发的业务过程。V7.0 提供增强的需求跟踪、构建跟踪、企业测试管理,及部署跟踪的功能。这提供了从开发到部署的完整的审计跟踪,并扩展了跨生命周期的可追溯性。软件增强了开发流程并使之自动化,同时还提高了软件生命周期的可理解性、可预测性和可控制性。
  五、JIRA(商业)
  JIRA是集项目计划、任务分配、需求管理、错误跟踪于一体的商业软件。
  JIRA功能全面,界面友好,安装简单,配置灵活,权限管理以及可扩展性方面都十分出色。
  JIRA创建的默认问题类型包括New Feature、Bug、Task和Improvement四种,还可以自己定义,所以它也一是过程管理系统。
  Jira融合了项目管理、任务管理和缺陷管理,许多著名的开源项目都采用了JIRA。
  JIRA 是目前比较流行的基于Java架构的管理系统,由于Atlassian公司对很多开源项目实行免费提供缺陷跟踪服务,因此在开源领域,其认知度比其他的产品要高得多,而且易用性也好一些。同时,开源则是其另一特色,在用户购买其软件的同时,也就将源代码也购置进来,方便做二次开发。
  六、Mantis(开源)
  Mantis是一个基于PHP技术的轻量级的缺陷跟踪系统,其功能与前面提及的JIRA系统类似,都是以Web操作的形式提供项目管理及缺陷跟踪服务。在功能上可能没有JIRA那么专业,界面也没有JIRA漂亮,但在实用性上足以满足中小型项目的管理及跟踪。更重要的是其开源,不需要负担任何费用。不过目前的版本还存在一些问题,期待在今后的版本中能够得以完善。
  七、Bugzero 免费开源,跨平台)
  BUGZERO? 是一个多功能,基于网络 (web-based) 并在浏览器 (browser) 下运行的 Bug缺陷管理和跟踪系统 (bug tracking system),可用来记录,跟踪,并归类处理软件开发过程出现的 Bug 和硬件系统中存在的缺陷(defect)。 BUGZERO 也是一个完整的服务管理软件,包括集成服务台热线流程管理(Help Desk),可用来记录各种日常事务,变更请求,和问题报告,及追踪和处理各种客户讯问,反馈,和意见。
  BUGZERO 提供了一个可靠的中央数据库使公司内部团队成员以及外部客户能在任何地点任何时间进行协调和信息交流,并且使任何记录都有据可查。它使你省时省力。BUGZERO 不但使用方便,而且功能齐全,变通性好,能够灵活设置各种实际工作流程,满足你特定的业务和产品环境下的需求。这种灵活、易用的缺陷跟踪流程不仅增强了项目开发的质量,同时也提高了整个机构的生产效率。
 八、BugTracker(免费开源,跨平台)
  Bugtracker是一个完整的bug/issue管理系统.它使用Java Servlet作为web前台,MySQL数据库作为后台。
  九、JTrac(开源)
  JTrac是一个开源且可高度配置的问题追踪的Web应用程序。它是一个一般性问题,跟踪网络应用程序,可方便地实现定制,增加自定义字段和下拉式。其特点包括可定制的工作流程,实地一级的权限,电子邮件集成,文件附件和详细的历史观点。
  十、BugNet(开源)
  BugNet是一个不错的开源bug跟踪和项目管理系统
  十一、BugOnline(开源)
  BugOnline 是一个开源的BUG管理系统。其功能强大,易于使用。
  基于asp.net2.0 ,sql server 2005(包括Express 版),Ajax等技术.
  BugOnline 的一些特性:
  在线消息及E-mail自动通知功能。有新Bug及Bug分配给用户同时将自动通知用户。
  优秀的人员分配,工作量统计功能。
  居于项目角色的权限管理,工作规划,流程化。
  Bug状态统计,便于掌控项目进度。
  基于SSL的数据传输,确保数据不被截取,保证安全性。(也可设定为非SSL)
  强大的报表功能。
  十二、eTraxis(开源)
  eTraxis是基于网页的免费bug跟踪系统。主要特点是:完全自定义模板,先进的过滤器, LDAP支持,电子邮件通知,订阅报刊,提醒,灵活的权限管理,图形化的项目指标等。
  十三、URTracker(商业)
  URTracker 是一款通用的流程化的问题跟踪管理软件。它可以:
  帮助您集中管理各种类型的问题、工作任务、人员交互等事务;
  跟踪每个事务的处理过程;
  控制问题处理的流程;
  提供一个有效的协作平台,简化团队成员的交互,提升沟通效率;
  积累知识信息;
  帮助您进行统计和分析;
  十四、KisTracker
  KisTracker一款bug跟踪管理软件(原名叫:iTracker),功能强大,易于使用,是基于WEB方式的协同工作软件.
  它用于帮助公司和团队跟踪工作中的问题,管理和记录这些问题的处理过程.可以应用于:
  1.产品BUG跟踪
  2.任务跟踪
  3.服务跟踪
  4.各种处理问题跟踪
  十五、TestLink(开源)
  TestLink用于进行测试过程中的管理,通过使用TestLink提供的功能,
  可以将测试过程从测试需求、测试设计、到测试执行完整的管理起来,
  同时,它还提供了好多种测试结果的统计和分析,使我们能够简单的开始测试工作和分析测试结果。
  TestLink 是sourceforge的开放源代码项目之一。作为基于web的测试管理系统,TestLink的主要功能包括:测试需求管理 测试用例管理测试用例对测试需求的覆盖管理 测试计划的制定 测试用例的执行 大量测试数据的度量和统计功能。

posted @ 2014-08-12 09:31 顺其自然EVO 阅读(568) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 67 68 69 70 71 72 73 74 75 下一页 Last 
<2025年4月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜