功能測試涉及了軟件在功能上正反兩面的測試,而非功能測試就是所有其他方面的測試。非功能測試包括性能、負載、安全、可靠性和其他很多方面。非功能測試有時也被稱作行為測試或質量測試。非功能測試的眾多屬性的一個普遍特征是一般不能直接測量。這些屬性是被間接地測量,例如用失敗率來衡量可靠性或圈復雜度,用設計審議指標來評估可測性。
國際標準化組織(ISO)在ISO 9216和ISO 25000:2005中定義了幾個非功能屬性。這些屬性包括:
可靠性
軟件使用者期望軟件能夠無誤運行。可靠性是度量軟件如何在主流情形和非預期情形下維持它的功能,有時也包括軟件出錯時的自恢復能力。例如,自動定時保存現行文件的功能就可以歸類到可靠性。
可用性
如果用戶不明白應該如何使用,那么,即使是零差錯的軟件也會變得毫無用處。可用性測量的是用戶
學習和控制軟件以達到用戶需求的容易程度。進行可用性研究、重視顧客反饋意見和對錯誤信息和交互內容的檢查都能提高可用性。
可維護性
可維護性描述了修改軟件而不引入新錯誤所需的
工作量。產品代碼和測試代碼都必須具備高度的可維護性。團隊成員對代碼的熟悉程度、產品的可測性和復雜度都對可維護性有影響。
可移植性
可移植性指一種計算機上的軟件轉置到其它計算機上的能力。軟件移植是實現功能的等價聯系,而不是等同聯系。從狹義上講,是指可移植軟件應獨立于計算機的硬件環境;從廣義上講,可移植軟件還應獨立于計算機的軟件,即高級的標準化的軟件,它的功能與機器系統結構無關,可跨越很多機器界限。
性能測試目的是驗證軟件系統是否能夠達到用戶提出的性能指標,同時發現軟件系統中存在的性能瓶頸,優化軟件,最后起到優化系統的目的。性能測試類型包括壓力測試、負載測試,強度測試,容量測試等。因為各屬性之間在范圍上有重疊,很多非功能屬性的名字是可以通用的。
壓力測試
一般來說,壓力測試的目的是要通過模擬比預期要大的工作負載來讓只在峰值條件下才出現的缺陷曝光。內存泄漏、競態條件、
數據庫中的線程或數據行之間的死鎖條件、和其他同步問題等等,都是壓力測試能發掘出來的常見缺陷。 壓力測試主要是為了測試硬件系統是否達到需求文檔設計的性能目標,譬如在一定時期內,系統的cpu利用率,內存使用率,磁盤I/O吞吐率,網絡吞吐量等。
負載測試
負載測試是要探討在高峰或高于正常水平的負載下,系統或應用軟件會發生什么情況。例如,一個網絡服務的負載測試會試圖模擬幾千名用戶同時連線使用該服務。測試的主要是軟件系統的性能,譬如軟件在一定時期內,最大支持多少并發用戶數,軟件請求出錯率等。
平均無故障時間(MTBF)測試
MTBF測試是測量系統或應用軟件在出錯或當機前的平均運行時間。這一測試有幾個變體,包括平均無錯時間(MTTF)或平均無當機時間(MTTC)。技術含義略有不同,但實踐上,這些詞匯都是一個意思。
低資源測試
低資源測試是要確定當系統在重要資源(內存、硬盤空間或其他系統定義的資源)降低或完全沒有的情況下會出現的狀況。重要的是要預估將會發生什么,例如為文件存盤而無足夠空間、或一個應用程序的內存分配失敗時將會發生什么。
容量測試
與負載測試非常相似,容量測試一般是用來執行服務器或服務測試。目的是要確定系統最大承受量,譬如系統最大用戶數,最大存儲量,最多處理的數據流量等。容量模型通常建立在容量測試數據基礎上。有了這些數據,營運團隊(Operations)就能定計劃什么時候增加系統容量:要么增加單機資源,如RAM、CPU和磁盤空間等;要么干脆增加計算機數目。
重復性測試
重復性測試是為了確定重復某一程序或場景的效果而采取的一項簡單而“粗暴”(brute force)的技術。這個技術的精髓是循環運行測試直到達到一個具體界限或臨界值,或者是不妙的境況。舉個例子,一個操作也許會泄漏20字節的內存。這并不足以在軟件的其他地方產生任何問題,但如果測試連續運行2000次,泄漏就可以增長到4萬字節。如果是提供核心功能的程序有泄漏,那么這個重復性測試就抓到了只有長時間連續運行該軟件才能發現的內存泄漏。通常有更好的辦法來發現內存泄漏,但有時候,這種簡單“粗暴”的方法也可以很有效。
兼容性測試
兼容性測試是指測試軟件在特定的硬件平臺上、不同的應用軟件之間、不同的操縱系統平臺上、不同的網絡等環境中是否能夠很友好的運行的測試。主要測試軟件是否能在不同的操作系統平臺上兼容,或測試軟件是否能在同一操作平臺的不同版本上兼容;軟件本身能否向前或向后兼容;測試軟件能否與其他相關的軟件兼容;數據兼容性測試,主要是指數據能否共享等。
安全性測試
安全性測試是檢查系統對非法侵入的防范能力。主要包括用戶認證、系統網絡安全和數據庫安全方面的測試。安全測試期間,測試人員假扮非法入侵者,采用各種辦法試圖突破防線。例如:想方設法截取或破譯口令;專門開發軟件來破壞系統的保護機制;故意導致系統失敗,企圖趁恢復之機非法進入;試圖通過瀏覽非保密數據,推導所需信息等。理論上講,只要有足夠的時間和資源,沒有無法進入的系統。因此系統安全設計的準則是使非法侵入的代價超過被保護信息的價值,此時非法侵入者已無利圖。
輔助功能測試
輔助功能測試保證軟件公司開發的軟件能被傷殘人使用。其中任何應用程序都必須測試的特性包括:操作系統的設置測試、“內置”輔助特性的測試(包括Tab 鍵順序、熱鍵和快捷鍵)、編程訪問的測試、以及輔助的技術工具的測試。輔助功能測試的一個重要方面就是使用輔助功能工具去測試應用程序, 這些工具包括,屏幕閱讀器、放大鏡、語音識別或者其他輸入程序。
本地化測試
本地化就是將軟件版本語言進行更改,本地化測試的對象是軟件的本地化版本。本地化測試的目的是測試特定目標區域設置的軟件本地化質量。本地化測試的環境是在本地化的操作系統上安裝本地化的軟件。從測試方法上可以分為基本功能測試,安裝/卸載測試,當地區域的軟硬件兼容性測試。測試的內容主要包括軟件本地化后的界面布局和軟件翻譯的語言質量,包含軟件、文檔和聯機幫助等部分。
配置測試
配置測試就是測試軟件是否和系統的其他與之交互的元素之間兼容,如瀏覽器、操作系統、硬件等,驗證被測軟件在不同的軟件和硬件配置中的運行情況。配置測試執行的環境是所支持軟件運行的環境。測試環境適合與否嚴重影響測試結果的真實性和正確性。硬件環境指測試必須的服務器、客戶端、網絡連接設備、打印機等,軟件環境指被測試軟件運行時的操作系統、軟件平臺、數據庫其他應用軟件構成的環境。
可用性測試
可用性測試是在產品或產品原型階段實施的通過觀察或訪談或二者相結合的方法,發現產品或產品原型存在的可用性問題,為設計改進提供依據。可用性測試不是用來評估產品整體的用戶體驗,主要是發現潛在的誤解或功能在使用時存在的錯誤。可用性測試適于解決的問題:確定測試產品的可用性水平;與預期目標、與競爭對手、與老版設計相比的可用性水平;比較不同方案,確定哪個方案更加可行。
一些在設計階段能幫助發現潛在的性能問題的技巧:
提出疑問:
找出有潛在性能問題的地方。對網絡交通的擁塞狀況、內存管理的效率、數據庫設計的合理性、或其他任何有關地方提出疑問。即使你并沒有性能設計的解決方案,而只是通過讓其他團隊成員考慮性能問題,測試工程師也一樣能夠產生很大的影響力。
考慮全局:
不是片面地考慮局部的優化,而是考慮全面的用戶場景。你將會在整個開發過程中有相對充足的時間深入性能場景的細節,但是在設計階段的時間最好是花費在考慮從頭到尾的場景上。
明確目標:
象“響應時間應該很快”這樣的目標是不可度量的。應用SMART(Specific-具體的, Measurable-可度量的, Achievable-可實現的, Relevant-相關的, Time-bound – 有時限的)標準來設計目標。舉個例子,“每個用戶操作的執行時間必須不超過100毫秒,或上一版本的10%的時間之內將控制權返回應用程序”。
還有一個要考慮的技巧是預測哪里可能有性能問題,或者說分辨出哪些操作對用戶來說是最重要的,從而是需要度量的。而往往最有效的辦法就是在設計階段就定義這些場景。
注:本文為《微軟的軟件測試之道》一書第12章內容以及網絡收集后整理后的知識筆記,感謝本書作者Alan Page及網絡內容相關作者。
摘要: 在上一次的selenium教程中我們介紹了如何使用maven自動配置selenium環境以及如何使用Maven來配置TestNG,那么這次的課程主要講一下ReportNG的配置,在講之前這塊之前先講講為什么要講reportNG,大家在使用TestNG時一定會發現其本身的報告生成不但簡陋而且相當的不美觀,而ReportNG正是一款為TestNG量身定做的報告生成插件,其報告美觀、簡約、清...
閱讀全文
1、名詞說明
1)主系統
制作
Linux系統并不是在一無所有的裸機上完成的,需要一個幫助我們制作系統的系統,這個系統就稱為“主系統”。我們制作的系統就是依靠這個主系統來逐步完成的,因此主系統的選擇非常重要。
2)目標系統
目標系統就是我們要完成的系統
3)臨時系統
在制作目標系統 的過程中會有一個小型的過渡系統,這個系統在輔助制作完成目標系統后就不再使用了,所以稱為臨時系統。
4)編譯工具
將Binutils(匯編工具)、GCC(編譯器)合稱為編譯工具。
5)工具鏈
將Binutils(匯編工具)、GCC(編譯器)和GLibc(標準C函數庫)的組合稱為工具鏈,有時候也會將一些需要用到的函數庫作為工具鏈的一部分,使用工具鏈生成的可執行文件總是使用該工具鏈中的函數庫。
在整個制作過程中,各個階段都會產生工具鏈,為了能清楚并準確的表達某個工具鏈,對各個階段的工具鏈名稱做如下規定:
原工具鏈:主系統的工具鏈
預工具鏈:用于生成臨時工具鏈的工具鏈
臨時工具鏈:用于生成臨時系統的工具鏈
目標工具鏈:用于生成目標系統的工具鏈
6)輔助命令
在編譯軟件包的過程中,除了工具鏈以外還需要一些命令的參與,如make,這些命令合稱為輔助命令
7)工具鏈環境
將工具鏈連同輔助命令合稱為工具鏈環境,不同的階段會出現不同的組合,下面對各個階段的工具鏈環境的稱呼做如下規定:
預工具鏈環境:預工具鏈+主系統的輔助命令及基本函數庫
臨時工具鏈環境:臨時工具鏈+臨時系統中的輔助命令及基本函數庫
目標工具鏈環境:目標工具鏈+目標系統中的輔助命令及基本函數庫
8)運行環境
在一個運行的系統中可以存在多個不同的環境,這些環境中有各自的根目錄及環境設置,這樣的環境稱為運行環境。在制作過程中各個階段會處于不同的運行環境,這里對稱呼做如下規定
主系統運行環境:-----
目標系統運行環境:目標系統所在目錄為根目錄的運行環境
9)純凈度
這里的純凈度并不是一個計量單位,而是用于表達某系統與其它系統的相關性,如果一個系統的運行依賴于另一個系統,那么這個系統是不純凈的。我們的目標是制作一個完全獨立運行的系統。而且不管主系統是什么,只要目標系統制作出來了,那么目標系統就不會因為主系統的不同而有差異。
10)頭文件
用于編譯的一類文件,一般以.h作為文件的后綴,存放了函數的接口描述、結構體信息等程序設計相關的內容。
2、源代碼的編譯過程
1.數據庫連接配置
<span style="font-family:'宋體', SimSun;font-size:16px;">//數據庫連接配置<br>def db = [<br> url:'jdbc:h2:mem:groovy',<br> user:'root',<br> password:'root',<br> driver:'org.h2.Driver'<br>];<br></span>
2.創建數據庫連接,這里使用到Groovy的Sql類。 <span style="font-family:'宋體', SimSun;font-size:16px;">//創建數據庫連接<br>def sql = Sql.newInstance(db.url, db.user, db.password, db.driver);<br></span>
3.創建數據庫表
<span style="font-size:14px;font-family:'宋體', SimSun;">//創建數據庫表<br>sql.execute('''<br> CREATE TABLE account(<br> id integer NOT NULL,<br> name varchar(20),<br> url varchar(100)<br> )<br>''');<br> </span>
使用了groovy.sql.Sql類的execute方法執行一條SQL命令,在數據庫groovy中創建了表account。
4.向數據庫表中寫入數據,并查詢寫入的數據
<span style="font-family:'宋體', SimSun;font-size:16px;">//寫入數據<br>def datas=[<br> [100, 'Jack', 'http://www.jack.net'], <br> [101, 'Groovy', 'http://groovy.com'], <br> [102, 'Apache', 'http://apache.org']<br>];<br>datas.each { param-><br> sql.execute('INSERT INTO account(id, name, url) values(?,?,?)', param);<br>}<br>println('Insert After:');<br>sql.eachRow('SELECT id, name, url FROM account') { row-><br> printf('|%d|%s|%s|\n', row.id, row.name, row.url);<br>}<br></span>
從4中的程序可以看出,向表account中寫入3條數據記錄,然后查詢并遍歷出查詢結果,再這一過程中使用了Groovy的閉包特性,列表數據結構。
下面是查詢的結果:
<span style="font-family:'宋體', SimSun;font-size:16px;">Insert After:<br>|100|Jack|http://www.jack.net|<br>|101|Groovy|http://groovy.com|<br>|102|Apache|http://apache.org|<br></span>
5.查詢數據
<span style="font-family:'宋體', SimSun;font-size:16px;">//查詢第一行數據<br>def rs=sql.firstRow('SELECT * FROM account');<br>println('Query First Row:');<br>println(rs);<br></span>
Groovy的Sql類提供了大量的查詢方法(具體參見Groovy的API),上面5中的代碼是查詢第一條記錄,返回的類型是GroovyRowReasult,其實現了Map接口。打印輸出則是一個Groovy的Map類型表示。如下:
<span style="font-family:'宋體', SimSun;font-size:16px;">Query First Row:<br>[ID:100, NAME:ZhangSan, URL:http://aiilive.blog.51cto.com]<br></span>
6.更新數據
<span style="font-family:'宋體', SimSun;font-size:16px;">def name='ZhangSan';<br>def url='http://aiilive.blog.51cto.com';<br>sql.executeUpdate("UPDATE account SET name=$name, url=$url where id=100");<br>println('Update After:');<br>sql.eachRow('SELECT id, name, url FROM account') { row-><br> printf('|%d|%s|%s|\n', row.id, row.name, row.url);<br>}<br></span>
7.刪除數據
<span style="font-family:'宋體', SimSun;font-size:16px;">//刪除指定條件的數據<br>name='Groovy';<br>sql.executeUpdate('DELETE FROM account WHERE name = ?', [name]);<br>name='Apache';<br>sql.execute('DELETE FROM account WHERE name=:name', ['name':name]);<br>println('Delete After:');<br>sql.eachRow('SELECT id, name, url FROM account') { row-><br> printf('|%d|%s|%s|\n', row.id, row.name, row.url);<br>}<br></span>
8.使用DataSet來處理數據
DataSet是Sql類的直接子類,用DataSet來操作數據庫表更加有操作對象的樣子。
<span style="font-family:'宋體', SimSun;font-size:16px;">def account=sql.dataSet('account');<br><br>account.add([id:103, name:'h2', url:'http://h2.org']);<br><br>name='51cto';<br>url='http://www.51cto.com';<br>account.add([id:104, name:name, url:url]);<br><br>println('DataSet Update After');<br>account.eachRow('SELECT id, name, url FROM account') { row-><br> printf('|%d|%s|%s|\n', row.id, row.name, row.url);<br>};<br>def accountRows=account.rows();<br>accountRows.each { row-><br> printf('|%d|%s|%s|\n', row.id, row.name, row.url);<br>}<br></span>
如上dataSet的參數account表示數據庫中的表名。account是一個DataSet類型的對象,通過add方法想數據庫表中添加一條記錄,通過rows方法返回數據庫表中的所有記錄,如果rows方法添加參數則可以實現分頁的功能。
上面通過groovy.sql包提供的API實現了數據庫的基本操作,而該包中的類的其它更多的方法能夠實現更豐富的操作。下面介紹數據庫表和對象的映射操作以及集成Spring來操作數據庫表。 數據庫表和對象的映射操作:
1.準備工作
創建一個抽象的類SqlQuery
<span style="font-family:'宋體', SimSun;font-size:16px;">import groovy.sql.*;<br><br>abstract class SqlQuery {<br><br> def sql;<br> def query;<br><br> def SqlQuery(sql,query){<br> this.sql=sql;<br> this.query=query;<br> }<br><br> def execute(){<br> def rowList=sql.rows(query);<br> def results=[];<br> def size=rowList.size();<br> 0.upto(size-1) { index-><br> results <<this.mapRow(rowList[index]);<br> }<br> return results;<br> }<br><br> def abstract mapRow(row);<br>}<br></span>
創建一個Account類,其屬性對應account表的字段
<span style="font-family:'宋體', SimSun;font-size:16px;">class Account {<br><br> def id;<br> def name;<br> def url;<br><br> @Override<br> public String toString() {<br> return "|$id|$name|$url|";<br> }<br>}<br></span>
創建一個AccountQuery類繼承SqlQuery類并實現其中的抽象方法rowMap
<span style="font-family:'宋體', SimSun;font-size:16px;">import com.demo.db.SqlQuery;<br><br>class AccountQuery extends SqlQuery {<br><br> def AccountQuery(sql){<br> super(sql, 'SELECT id, name, url FROM account');<br> }<br><br> @Override<br> public Object mapRow(Object row) {<br> //映射非常之靈活<br> //def acc=new Account(id:row.getAt('id'),name:row.getAt('name'),url:row.getAt('url'));<br> //def acc=new Account(id:row.getAt(0),name:row.getAt(1),url:row.getAt(2));<br> def acc=new Account(<br> id:row.getProperty('id'),<br> name:row.getProperty('name'),<br> url:row.getProperty('url'));<br> return acc;<br> }<br>}<br></span>
AccountQuery類實現了rowMap方法,正是該方法將對象和表記錄關聯起來的,即達到了Table - Object的映射效果。
注意:上面代碼中的注釋部分是實現同樣功能的不同寫法。
2.通過SqlQuery類來查詢account表的數據
<span style="font-family:'宋體', SimSun;font-size:16px;">//表映射對象查詢<br>def accountQuery=new AccountQuery(sql);<br>def accList=accountQuery.execute();<br>println 'Table <-> Object Query: ';<br>accList.each { acc-><br> println acc.toString();<br>}<br></span>
accList則是Account對象的一個數組集合,這樣就實現了數據庫表和對象的映射操作。
集成Spring來操作數據庫表:
1.準備工作
Spring提供了一個MappingSqlQuery類,我們可以用AccountQuery繼承該類并實行其中的rowMap方法來達到數據庫表和對象的映射。
<span style="font-family:'宋體', SimSun;font-size:16px;">import com.demo.db.Account;<br><br>import org.springframework.jdbc.object.MappingSqlQuery<br><br>class AccountQuery extends MappingSqlQuery {<br><br> def AccountQuery(ds){<br> super(ds,'SELECT id, name, url FROM account');<br> this.compile();<br> }<br><br> @Override<br> protected Object mapRow(ResultSet rs, int rowNumber) throws SQLException {<br> def acc=new Account(<br> id:rs.getInt('id'),<br> name:rs.getString('name'),<br> url:rs.getString('url'));<br> return acc;<br> }<br>}<br></span>
需要注意的地方是Spring的MappingSqlQuery類的帶參數構造方法需要提供一個DataSource對象和查詢的SQL命令。
創建一個Account類的DAO類,AccountDAO來實現數據庫的操作,可以定義一個接口,然后另外實現該接口。應用程序操作數據庫則只需要依賴定義的接口即可。這里省略了接口的定義。
<span style="font-family:'宋體', SimSun;font-size:16px;">class AccountDao {<br><br> def ds;<br><br> def getAccounts(){<br> def aq=new AccountQuery(ds);<br> return aq.execute();<br> }<br>}<br></span>
AccountDao有一個getAccounts方法,通過該方法則可以獲取到表account的所有記錄,通過AccountQuery的Mapping映射,將返回一個集合對象。
2.通過AccountDao類操作數據庫
<span style="font-family:'宋體', SimSun;font-size:16px;">//集成Spring<br>def ds=new DriverManagerDataSource(db.url, db.user, db.password);<br>def accountDao=new AccountDao(ds:ds);<br>accLists=accountDao.getAccounts();<br>println 'Spring MappingSqlObject Query: ';<br>accList.each { acc-><br> println acc.toString();<br>}<br></span>
至此Groovy操作數據庫就到這里了。Groovy讓Java操作數據庫變得輕巧許多,同時又沒有引入多余復雜的API負擔。了解PHP的數據庫操作就能很快感受到Groovy讓Java操作數據庫不那么繁瑣了。
題外話:
很遺憾過了這么就才反映過來,應該擁抱Groovy,在經歷學習的Python,PHP和Nodejs之后,就更應該在已有的Java知識的基礎上使用這個據說是"Java時代的王儲"的動態語言。固步自封是可怕的,停留在舒適區更是后果不堪設想。放下,才能更輕松的上路,才能走的更遠。
在面對動不動就SSH, SSM,TSH,JSF等框架堆砌Java應用的時候,會有那么一個夜晚,突然累了,疲憊了。人就像一只猴子被困在囚籠里,跳著千篇一律的舞蹈騙取欣賞,有自知索然無味卻不得以為之的和這囚籠糾纏在一起,不得自己。不久,就被發展的潮流拍到沙灘,碎巖之上。
面對生產效率和機器效率之間的取舍不見得能達成一致的協議,但技術服務于生產,想法化為產品,則更需要容易表達和實現這些東西的技術,把復雜的事情簡單化應該是技術追求的目標。
1、定義接口
使用interface來定義一個接口。接口定義同類的定義類似,也是分為接口的聲明和接口體,其中接口體由常量定義和方法定義兩部分組成。定義接口的基本格式如下:
[修飾符] interface 接口名 [extends 父接口名列表]{
[public] [static] [final] 常量;
[public] [abstract] 方法;
}
修飾符:可選,用于指定接口的訪問權限,可選值為public。如果省略則使用默認的訪問權限。
接口名:必選參數,用于指定接口的名稱,接口名必須是合法的Java標識符。一般情況下,要求首字母大寫。
extends 父接口名列表:可選參數,用于指定要定義的接口繼承于哪個父接口。當使用extends關鍵字時,父接口名為必選參數。
方法:接口中的方法只有定義而沒有被實現。
例如,定義一個用于計算的接口,在該接口中定義了一個常量PI和兩個方法,具體代碼如下:
public interface CalInterface { final float PI=3.14159f;//定義用于表示圓周率的常量PI float getArea(float r);//定義一個用于計算面積的方法getArea() float getCircumference(float r);//定義一個用于計算周長的方法getCircumference() } |
注意:
與Java的類文件一樣,接口文件的文件名必須與接口名相同。
實現接口
接口在定義后,就可以在類中實現該接口。在類中實現接口可以使用關鍵字implements,其基本格式如下:
[修飾符] class <類名> [extends 父類名] [implements 接口列表]{
}
修飾符:可選參數,用于指定類的訪問權限,可選值為public、abstract和final。
類名:必選參數,用于指定類的名稱,類名必須是合法的Java標識符。一般情況下,要求首字母大寫。
extends 父類名:可選參數,用于指定要定義的類繼承于哪個父類。當使用extends關鍵字時,父類名為必選參數。
implements 接口列表:可選參數,用于指定該類實現的是哪些接口。當使用implements關鍵字時,接口列表為必選參數。當接口列表中存在多個接口名時,各個接口名之間使用逗號分隔。
在類中實現接口時,方法的名字、返回值類型、參數的個數及類型必須與接口中的完全一致,并且必須實現接口中的所有方法。例如,編寫一個名稱為Cire的類,該類實現5.7.1節中定義的接口Calculate,具體代碼如下:
public class Cire implements CalInterface { public float getArea(float r) { float area=PI*r*r;//計算圓面積并賦值給變量area return area;//返回計算后的圓面積 } public float getCircumference(float r) { float circumference=2*PI*r; //計算圓周長并賦值給變量circumference return circumference; //返回計算后的圓周長 } public static void main(String[] args) { Cire c = new Cire(); float f = c.getArea(2.0f); System.out.println(Float.toString(f)); } } |
在類的繼承中,只能做單重繼承,而實現接口時,一次則可以實現多個接口,每個接口間使用逗號“,”分隔。這時就可能出現常量或方法名沖突的情況,解決該問 題時,如果常量沖突,則需要明確指定常量的接口,這可以通過“接口名.常量”實現。如果出現方法沖突時,則只要實現一個方法就可以了。下面通過一個具體的 實例詳細介紹以上問題的解決方法。
舊的商業模式已然涅槃,高度協作、通力創新的新型商業模式正在浴火重生。現在,任何行業、任何職位的人,都需要具備創造性解決問題的能力。
更具挑戰的是,在這個永不停息的商業環境中,你的創新能力必須時刻就位,以應對隨時撲面而來的需求——而這也正是你的腦袋最容易變“磚”的時候。然而,在一個快速發展的公司中,每天都能獲得新的靈感對于你或你的團隊來說都是件不太可能的事情,而且尋找靈感的道路也千變萬化。出去散個步啟發靈感、換換眼前風景或看一集《Shower Principle》【《我為喜劇狂》(30 Rock)第六季第15集《The Shower Principle》,這一集是關于如何用創意打動上司的】,這些方法在我身上從未連續生效過兩次。
幸運的是,我發現了一些旁門左道的小技巧,在你無計可施的時候,或許可以幫上忙。
1.擁抱最后1分鐘的創新點子
在最后一分鐘有時會發生神奇的事情。這時,人們的思維往往更清晰,也更歇斯底里地渴望突破。當deadline逐步逼近而我的團隊還掙扎于困境時,我會在最后關頭要求隊員向整個團隊展示他們的任何想法,不管那些想法聽起來是多么“不言而喻”或滑稽可笑。“假設你能全權決定這個項目……。”你無法想象當你把這句話告訴一群創新人士時,它所起到的緩解壓力的效果。
值得注意的是,這個方法只在最后關頭有效,而你必須身先士卒,這樣你的團隊才能自由地表達想法。你可以嘗試在項目的早些時候賦予團隊這種自由權,但他們可能并不會相信你而放開手腳去嘗試。等你感覺到團隊的緊張氣氛時,再把這招使出來。
2.找一些你能看得見摸得著的東西
當你的初步方案形成時,找個可觸碰的東西放在屋里。比方說,一件可以讓你聯想到你所構思產品最終形態的工藝品;它能提醒你,前人做過什么,哪些又可改進。再比如,競爭對手的某件產品,一塊建筑材料,成品的一個小部件,一本客戶群體一致的雜志等等。任何能夠從視覺上喚醒你的點子并且讓那個點子壯大的東西都是不錯的選擇。觸覺通常能夠激發你的大腦功能,而相比你頭腦中的模糊概念,一個看得見摸得著的東西更能激發創造力。
3. 歸檔你的老點子
對了,點子不會那么容易就死,它們對我們所花的心思來說如此寶貴,我們不竭余力尋找任何機會讓它們起效。
別隨便拋棄它們,你要做的是一邊堆積一邊繼續前進。將自己從老點子中解放出來,繼續前進去想些更新、更好和更有建設性的鬼點子。
4.壓縮團隊至“奮斗”規模
當我的公司規模甚小,小到只有三個聯合創始人時,通常其中一個不得不與另外兩個爭辯,以便讓創意之河繼續流動。民主是你的最好朋友也可能是你的刻薄叔叔,但至少它能讓你站起來,堅守自己所堅信的東西。
不幸的是,當一個公司越做越大,奮斗的精神將趨于消散。當你的創意團隊規模變大時,你很容易變得飄飄然,呼吁智囊團為“大團隊”而開動大腦。
壓縮你的團隊至三四個人,便能再次激起雄辯的火花,在創新的過程中挖掘更深的內涵。不妨將自己(和你的同事)逼迫到某個位置,在那兒,大家都明白,你不得不辯護自己的最佳創意,創新持久戰才得以進行,正如需求實際上是革新之母一樣。
軟件項目/產品的質量問題一直困擾軟件企業、監理方和甲方,如何預防、發現、治理軟件項目/產品質量問題,是目前我國it發展面臨巨大的挑戰,這也是it發展過程中關注的主要問題。軟件企業、甲方和監理方在研發過程中常常要面臨很多難題:
(1)質量的概念與定義;(2)軟件的質量要素;(3)軟件質量評價的準則;(4)iso 9000軟件質量體系結構;(5)軟件質量保證過程;(6)質量管理大師簡介;(7)質量管理的發展歷程;
2、軟件質量與質量管理
(1)軟件質量面臨的挑戰及模糊認識;(2)軟件質量基礎;(3)軟件發生質量問題的根本原因及對策;(4)軟件質量工程體系;(5)軟件質量控制方法、模型與工具;(6)軟件全面質量管理;
3、軟件質量管理工具選型;(1)軟件質量管理粒度分析;(2)軟件質量管理工具決策分析;(3)介紹商用質量管理工具;(4)介紹開源質量管理工具;
4、質量的防范策略
(1)質量預防的哲學;(2)為什么擔心質量;(3)發布有質量問題產品的商業影響;(4)生命周期成本計算概念;(5)質量防范計劃;(6)pareto分析;(7)趨勢分析;
5、高質量的軟件需求
(1)需求的概念;(2)需求開發的主要困難與應對;(3)需求調查、需求分析的質量控制;(4)什么是合格的軟件需求規格說明書;(5)需求驗證與管理;(6)需求階段度量技術及相應的工具;
6、提高軟件設計質量
(1)軟件設計關鍵問題分析;(2)軟件設計策略方法;(3)軟件設計質量控制要點及評價標準;(4)典型系統架構、應用策略及對質量的影響;(5)軟件設計質量的分析與評價,方法、技術和工具;
7、高質量編程
(1)編程面臨的問題;(2)高質量代碼的特性;(3)代碼風格與編程規則;(4)關鍵的編程決策與編程質量;(5)提高程序質量的技術及度量技術與工具;(6)代碼審查、
單元測試的質量控制;(7)調整代碼達成質量目標;
(1)測試的常識與道理;(2)測試的現實;(3)測試方法應用之道;(4)測試目標實現的完整性和有效性;(5)測試過程的評審和質量保證;(6)軟件測試組織和管理;(7)軟件測試質量的量化質量管理技術與工具
9、軟件發布和維護的質量管理
(1)軟件構建(build)健康質量分析;(2)軟件發布質量標準定義;(3)軟件發布質量管理;(4)軟件維護質量管理;
10、軟件產品質量評價與選擇
(1)軟件產品的質量模型(勃姆與麥考爾模型);(2)軟件產品質量的度量方法;(3)軟件產品評價準則的定義;(4)
微軟軟件質量測試常用度量;
11、軟件度量技術
(1)軟件度量概述;(2)軟件測量技術基礎;(3)“目標驅動”的軟件度量;(4)軟件規模度量及
工作量估算;(5)面向功能設計(結構)的度量;(6)軟件測試相關度量;(7)軟件質量度量;
12、缺陷度量
(1)軟件質量屬性與度量;(2)理解與缺陷相關的各種度量數據;(3)使用缺陷度量數據做決策;(4)缺陷分布度量、缺陷密度、缺陷注入率、整體缺陷清除率與階段性缺陷清除率;(5)缺陷報告的質量;(6)缺陷分析工具及實踐;
13、測試的度量
(1)
測試用例的深度、質量和有效性;(2)測試執行的效率和質量;(3)缺陷報告的質量;(4)測試覆蓋度(測試整體的質量);(5)測試環境的穩定性或有效性;
14、成熟度度量(maturity metrics)
(1)組織度量;(2)資源度量;(3)培訓度量;(4)文檔標準化度量;(5)數據管理與分析度量;(6)過程質量度量;
15、管理度量(management metrics)
(1)
項目管理度量(如里程碑管理度量、風險度量、作業流程度量、控制度量等);(2)質量管理度量(如質量審查度量、質量測試度量、質量保證度量等);(3)
配置管理度量(如式樣變更控制度量、版本管理控制度量等);(4)個人能力成熟度度量;(5)團隊能力成熟度度量;
16、
軟件開發項目規模度量(size measurement)
(1) 功能點分析(fpa:function points analysis);(2) 代碼行(loc:lines of code);(3) 德爾菲法(delphi technique);(4) cocomo模型;
方法一:
既然是腳本串行執行,那在場景設計中必然是要用多個腳本,要注意的是需要將Scenario Schedule中的Schedule by設置為Group的模式.然后按實際需要依次設置每個腳本的Schedule.要事先計算好每個腳本的整個執行時間,方便定義后續腳本的開始時間(設置Start Group).
方法二:
使用定時任務執行:
首先創建并設置好要跑的個
測試場景,再創建一個一個批處理程序按先后順序調用這幾個個場景進行測試,最后通過
Windows的定時任務設定批處理的執行時間
寫一個批處理文件
批處理示例如下:
cls SET M_ROOT="D:\Program Files\MI\Mercury LoadRunner\bin\" %M_ROOT%\wlrun.exe -TestPath "D:\Program Files\MI\Mercury LoadRunner\scenario\Test\TestScen_1.lrs" -Run %M_ROOT%\wlrun.exe -TestPath "D:\Program Files\MI\Mercury LoadRunner\scenario\Test\TestScen_2.lrs" -Run %M_ROOT%\wlrun.exe -TestPath "D:\Program Files\MI\Mercury LoadRunner\scenario\Test\TestScen_3.lrs" -Run |
這種方式比較靈活,但需要注意在Result Settings中設置“Automatically create a results directory for each scenario execution”,以免后面的測試結果覆蓋了前面的。
補充:
如果想做腳本的定時執行,其實也可以用多場景這種方式實現
1.添加要測試的場景A
2.添加一個跟測試無關的場景B,該場景里面思考時間設置自己設置,盡可能設計得能撐到自己想跑腳本的那個時間段
3.設置腳本串行執行,先執行B,執行多長時間后(此時長自己定義,基本是這個時長結束后就是去執行自己要定點執行的A場景)
4.當然最直接的辦法就是用定時任務去執行自己的場景,這樣就不需要用多場景了。
Selenium 是啥?
Selenium RC是啥?
Webdriver 又是啥?
RC 和 Webdriver 是啥關系?
Webdriver 和編程語言啥關系?
Selenium 能并行執行腳本嘛?
這里蟲師用簡單方式,告訴你,他們錯綜復雜的關系。理順了它們之間的關系才能真正使用它。
Selenium 是什么?
Selenium 是
web自動化測試工具集,包括IDE、Grid、RC(selenium 1.0)、WebDriver(selenium 2.0)等。
Selenium IDE 是firefox瀏覽器的一個插件。提供簡單的腳本錄制、編輯與回放功能。
Selenium Grid 是用來對測試腳步做分布式處理。現在已經集成到selenium
server 中了。
RC和WebDriver 更多應該把它看成一套規范,在這套規范里定義客戶端腳步與瀏覽器交互的協議。以及元素定位與操作的接口。
WebDriver是什么?
對于剛接觸selenium自動化測試的同學來說不太容易理解API是什么,它到底和編程語言之是什么關系。
http://www.w3.org/TR/2013/WD-webdriver-20130117/
當初,在剛學selenium (webdriver)的時候花了一個星期來翻譯這個文檔,后來也沒弄明白,它是啥。其實它就是一層基礎的協議規范。
假如說:Webdriver API(接口規范)說,我們要提供一個頁面元素id的定位方法。
require "selenium-webdriver" #導入ruby版的selenium(webdriver) find_element(:id, "xx") #id定位方法 |
C#的webdriver模塊是這么實現的:
using OpenQA.Selenium; using OpenQA.Selenium.Firefox; //導入C#版的selenium(webdriver) FindElement(By.Id("xx")) //id定位方法 |
python的webdriver模塊是這么實現的:
from selenium import webdriver #導入python版的selenium(webdriver) find_element_by_id("xx") #id定位方法 |
import org.openqa.selenium.*; import org.openqa.selenium.firefox.FirefoxDriver;//導入java版的selenium(webdriver) findElement(By.id("xx")) //id定位方法 Robot Framework + selenium |
因為Robot Framework 對于底層過于封裝,所以,我們看不到語言層面的方法定義。所以,Robot Framework 提供給我們的方法如下:
1、導入Robot Framework 版本的selenium(webdriver)
2、使用id方法
Click element
Id=xx
需要說明的是 webdriver API 只提供了web頁面操作的相關規范,比如元素定位方法,瀏覽器操作,獲取web頁元素屬性等。
Webdriver 如何組織和執行用例?
對不起,webdriver 不會。
把寫好這些操作頁面元素的方法(用例)組織起來執行并輸入測試結果,是由編程語言的單元測試框架去完成的。如java 的junit和testng單元測試框架,python 的unittest單元測試框架等。
Selenium RC 和WebDriver 什么關系?
RC和 WebDriver 類似,都可以看做是一套操作web頁面的規范。當然,他們的工作原理不一樣。
selenium RC 在瀏覽器中運行 JavaScript 應用,使用瀏覽器內置的 JavaScript 翻譯器來翻譯和執行selenese 命令(selenese 是 selenium 命令集合) 。
WebDriver 通過原生瀏覽器支持或者瀏覽器擴展直接控制瀏覽器。WebDriver 針對各個瀏覽器而開發,取代了嵌入到被測 Web 應用中的 JavaScript。與瀏覽器的緊密集成支持創建更高級的測試,避免了JavaScript 安全模型導致的限制。除了來自瀏覽器廠商的支持,WebDriver 還利用操作系統級的調用模擬用戶輸入。
看樣子webdriver 更牛B一些。為了保持向兼容,所以selenium 2.0中,RC 和webdriver 并存,但說起selenium 2.0 一般指的是webdriver 。
并行與分布式的區別
有同學好奇如何并行的執行測試用例,并行要求“同時”執行多條用例,這個也是由編程語言的多線程技術實現的。
你會問Selenium Grid 不是可以實現分布式執行么? 分布式的概念是寫好一條用例可以調用不同的平臺執行,如 A電腦上有一個測試用例,可以調用B電腦(linux)的 Firefox瀏覽器來跑A電腦上的測試用例;也可以調用C電腦(windows)的 Chrome瀏覽器來跑A電腦上的測試用例。這是分布式的概念。
Selenium如何能做移動端測試么?
這里我們以python 語言為例。
from selenium import webdriver
driver= webdriver.Chrome() #獲取瀏覽器驅動。拿到瀏覽器驅動driver 才能操作瀏覽器所打找的頁面上的元素。
我們把驅動展開是這樣的
from selenium import webdriver driver = webdriver.Remote( command_executor='http://127.0.0.1:4444/wd/hub', desired_capabilities={'platform': 'ANY', 'browserName':chrome, 'version': '', 'javascriptEnabled': True }) |
驅動里包含了一些參數,代理服務器(URL)平臺,瀏覽器 ,瀏覽器版本等。
移動端的自動化測試工具Appium
從本質上來講,appium同樣繼承了WebDriver API的接口規范。Appium 同樣是支持多種編程語言的。這里仍然以python 為例子。
from appium import webdriver #導入python版的 appium(webdriver)模塊
#定義驅動的參數 desired_caps = {} desired_caps['platformName'] = 'Android' desired_caps['platformVersion'] = '4.2' desired_caps['deviceName'] = 'Android Emulator' desired_caps['appPackage'] = 'com.android.calculator2' desired_caps['appActivity'] = '.Calculator' driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps) |
這一次因為我們操作的是移動端的安卓。所以我們驅動的參數里就要指定平臺是'Android' ,版本是4.2 等信息。拿到驅動后,就可以操作安卓上的APP了。
由于
測試和開發各自所站角度的不同導致了,大家對同一個問題看法的不同,繼而導致做法上存在各自的差異,有的時候會因為一個或者兩個有爭議的問題吵得不可開交,其實都是沒有必要的。
在現實的
工作中卻是會存在的,如果真的遇到了這些問題,在流程正規的公司里解決起來是比較容易的,在流程混亂的公司里則比較難辦。區別在于:一旦遇到了有爭議的地方,通常的做法都是選擇將相關有爭議的人員召集起來大家一起開個會,然后各種闡述自己的主張,這時候大家通常會在會議上商量一個解決爭議問題的機制。例如,開發將問題轉交給需求設計人員,讓其進行判斷到底是采取開發的意見還是測試的意見,這里的話,有個不容忽視的點,那就是成本的控制。
縱然測試提出的意見很具有前瞻性和從產品設計的角度來說,能夠提高產品總的競爭力,由于系統上線的時間,和開發處理問題等進度各方面的綜合考慮,可能測試的意見也會在當前的版本內不予考慮,或許會加入到下一個版本考慮范疇內,從這點來說,測試提出的意見是有價值的;還有可能會出現需求設計人員的誤判,本身是一個很好的提議,由于需求設計人員沒有意識到自己設計出的需求文檔方面的漏洞而斷然去拒絕一個好的提議,在這種時候,作為測試人員自身的素質是否達標就能夠充分體現出來了,有的測試人員之間就不在堅持自己的主張,感覺反正是需求人員設計的,他們說好就是好,說不好就是不好,完全沒有自己任何的思想,而那些素質過硬的測試人員,他們會進一步去思考,他們提出的方案是否值得他們去堅持,如果要堅持自己的主張,那么堅持的依據是什么,要是放棄自己的主張,放棄的依據又在哪里?當發現是需求設計人員的錯誤時,這時素質過硬的測試人員會采取更加巧妙的方式和方法去和需求設計人員溝通和交流,溝通和交流看似好像就是和對方闡述一下自己的觀點,實際上難度卻比較大,當我們去贊同別人的時候,會很快拉進我們和對方的親近感,反之去否定對方的時候,卻很容易拉大和對方的代溝,導致無法說服對方,達成共識!后續的合作可能會因不斷積累的代溝,導致產生不同程度的芥蒂,造成事情處理起來不是那樣的順暢。
流程混亂的公司會出現的問題就是開發和測試可能會相互的指責,開發感覺測試玩命的測他系統,會想著讓測試按照他們的操作手法來使用系統,而測試人員這時也覺得很委屈,如果說只能按照開發人員設計出來的方法使用系統,那還不如讓開發自測系統算了,還要測試干嘛,不是無形中浪費公司測試資源嗎!特別對于一些找出的開發無法修復的問題,態度不好的開發,很有可能會和測試人員吵起來,其實可能很多人會疑問,那為什么不去制定相應的流程進行規范這些事情?流程的制定是一件很簡單的事情,難的是如何讓流程能夠走下去,之所以混亂是由于缺乏將流程貫徹到底的決心和腳踏實地的執行力,如果你此刻身處這種流程混亂的環境里,那么恭喜你,這正好是能夠磨練你盡快成長的訓練基地,會讓你在無形中思考問題不得不去全面,流程如果過于混亂,一般產品的質量基本都是沒有什么保障的,要求做完測試人員要把系統所以可能的風險在測試的時候都得注意到,只要這樣,才能避免上線后出的問題不是由于測試人員的漏測導致的,而是源于其他問題引起的。
當你不斷的在工作中,遇到有爭議的問題首先想到的都是去找相應的依據支持自己的觀點或者否定掉自己的觀點后,你所提的建議就會更具有價值,你自身的素質也就會不斷的得以提高!