轉自:https://blog.csdn.net/qq_15945247/article/details/78791017java
JUnit是一個開發源代碼的Java測試框架,用於編寫和運行可重複的測試。它是用於單元測試框架體系xUnit的一個實例(用於java語言)。主要用於白盒測試,迴歸測試。git
我的理解:每次軟件作版本迭代,爲防止引入新的問題,須要對重要功能的接口進行基本功能測試。此時能夠考慮作成自動化(在版本迭代較快,主要功能基本不變化的接口適用)web
以前本人測試使用JUnit3,目前JUnit4已經普及。JUnit 4是與JUnit3徹底不一樣的API,它基於Java 5.0中的註解、靜態導入等構建而成。JUnit 4更簡單、更豐富、更易於使用,並引入了更爲靈活的初始化和清理工做,還有限時的和參數化測試用例apache
JUnit3下載地址:https://pan.baidu.com/s/1jH9Kv90
JUnit4下載地址:https://pan.baidu.com/s/1qYLZC7aapi
在eclipse中新建工程,而後在configure build path中導入junit jar包,在eclipse的工程中引入Junit lib庫,而後能夠建立Junit Test Case或者Junit Test Suiteapp
這裏展現測試用例的編寫過程框架
測試要求dom
某數據平臺提供接口給第三方使用,第三方根據接口託管本身的數據。須要測試平臺提供的全部對外接口的功能,確保正常eclipse
準備工做單元測試
獲取提供給第三方的Api(jar包形式),在eclipse中新建工程,導入該jar包,導入JUnit包,新建package,針對每一個方法建立對應的測試類等,以下圖所示
目錄結構及類說明
在cn.cstor.wwy.test存放測試類,每一個方法對應一個測試類,好比平臺提供AddDevice接口,因此要新建一個TestAddDevice類,在TestAddDevice類中存在多個測試方法
package cn.cstor.wwy.test; import cn.cstor.wwy.test.util.Count; import java.io.UnsupportedEncodingException; import org.apache.thrift.TException; import cn.cstor.wwy.test.util.Const; import cn.cstor.wwy.test.util.CustomString; import cproc.datacube.client.api.ClientBaseApi; import cproc.datacube.client.api.ClientBaseApiService; import cproc.datacube.client.api.ClientDevelopApi; import cproc.datacube.client.api.ClientDevelopApiService; import cproc.datacube.client.entity.AppInfo; import cproc.datacube.client.entity.DeviceConditionInfo; import cproc.datacube.client.entity.ReObject; import cproc.datacube.client.entity.UserInfo; import junit.framework.TestCase; import java.lang.Math; //addDevice public class TestAddDevice extends TestCase{ CustomString cString = new CustomString(); AppInfo app = new AppInfo(); UserInfo user = new UserInfo(); ClientDevelopApi deveApi = new ClientDevelopApiService(); ClientBaseApi baseApi = new ClientBaseApiService(); Count ct = new Count(); int startct = 0; int endct = 0; protected void setUp() throws UnsupportedEncodingException, TException { user.setUserName(Const.USERNAME); user.setAccessId(Const.CERTIFICATE); app.setAppId(Const.APPID); app.setUserInfo(user); } protected void tearDown() throws TException { } //正經常使用例 public void testAddDevice() throws TException { //設置設備信息 startct = ct.getPoint(); DeviceConditionInfo deviceCon = new DeviceConditionInfo(); int x = (int)(Math.random()*Math.random()*Math.random()*1000000); deviceCon.setDeviceid("device" + x); deviceCon.setDip("192.168.10.1"); deviceCon.setServicecode("1"); deviceCon.setVrs("v0.1"); ReObject reObject = deveApi.addDevice(app,deviceCon); endct = ct.getPoint(); System.out.println(startct); System.out.println(endct); assertEquals(true,reObject.isSuccess()); assertEquals(startct - 1,endct); } //設備名爲空 public void testAddDeviceNullDevId() throws TException { startct = ct.getPoint(); DeviceConditionInfo deviceCon = new DeviceConditionInfo(); deviceCon.setDeviceid(""); deviceCon.setDip("192.168.10.1"); deviceCon.setServicecode("1"); deviceCon.setVrs("v0.1"); ReObject robj = deveApi.addDevice(app,deviceCon); endct = ct.getPoint(); assertEquals(false,robj.isSuccess()); assertEquals("查詢條件不足",robj.getMsg()); assertEquals(startct,endct); } //設備名稱太長 public void testAddDeviceLongDevName() throws TException { startct = ct.getPoint(); DeviceConditionInfo deviceCon = new DeviceConditionInfo(); String devid = cString.generateString(200); deviceCon.setDeviceid(devid); deviceCon.setDip("192.168.10.1"); deviceCon.setServicecode("1"); deviceCon.setVrs("v0.1"); ReObject reObject = deveApi.addDevice(app,deviceCon); endct = ct.getPoint(); assertEquals(false,reObject.isSuccess()); assertEquals("插入數據失敗!",reObject.getMsg()); assertEquals(startct,endct); } //ip地址爲空 public void testAddDeviceNullIP() throws TException { //設置設備信息 startct = ct.getPoint(); DeviceConditionInfo deviceCon = new DeviceConditionInfo(); int x = (int)(Math.random()*Math.random()*Math.random()*1000000); deviceCon.setDeviceid("device" + x); deviceCon.setDip(""); deviceCon.setServicecode("1"); deviceCon.setVrs("v0.1"); ReObject reObject = deveApi.addDevice(app,deviceCon); endct = ct.getPoint(); assertEquals(true,reObject.isSuccess()); assertEquals(startct - 1,endct); } //ip格式不正確 public void testAddDeviceWrongIP() throws TException { //設置設備信息 startct = ct.getPoint(); DeviceConditionInfo deviceCon = new DeviceConditionInfo(); int x = (int)(Math.random()*Math.random()*Math.random()*1000000); deviceCon.setDeviceid("device" + x); deviceCon.setDip("123.12.25.23.212"); deviceCon.setServicecode("1"); deviceCon.setVrs("v0.1"); ReObject reObject = deveApi.addDevice(app,deviceCon); endct = ct.getPoint(); assertEquals(true,reObject.isSuccess()); assertEquals(startct - 1,endct); } }
在cn.cstor.wwy.test.util中存放一些常量信息
Const.java:存放用戶認證信息,應用信息,測試建立表名
package cn.cstor.wwy.test.util; public interface Const { // user info String USERNAME = "shenpp"; String CERTIFICATE = "C2HLBNBWMTUWMDI1NDCXNTI2MQ=="; String APPID = "0542051559"; String TABLENAME="CREATEBYINTERFACE"; }
Count.java:獲取積分方法 //測試須要對比積分,可是沒有藉口查詢,只能經過web頁面查詢,故增長該方法
package cn.cstor.wwy.test.util;
public class Count { public int getPoint() { int count = 0; String url = "http://192.168.10.105:8080/queryPointsForTest?uid=3450&accessid=C2HLBNBWMTUWMDI1NDCXNTI2MQ=="; try { String result = HttpUtil.getHttpContent(url,""); String[] res1 = result.split(":"); String[] res2 = res1[1].split("}"); count = Integer.valueOf(res2[0]).intValue(); } catch (Exception e) { e.printStackTrace(); } return count; } }
CustomString.java :生成一段隨機字符串,測試使用
package cn.cstor.wwy.test.util;
import java.util.Random;
public class CustomString { public String generateString(int clength) { String base = "abcdefghijklmnopqrstuvwxyz"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < clength; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } }
HttpUtil.java :設置http訪問的參數
package cn.cstor.wwy.test.util; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; public class HttpUtil { public static String getHttpContent(String url,String parameterData ) throws Exception { HttpURLConnection connection = null; // String content = ""; OutputStream outputStream = null; OutputStreamWriter outputStreamWriter = null; InputStream inputStream = null; InputStreamReader inputStreamReader = null; BufferedReader reader = null; StringBuffer resultBuffer = new StringBuffer(); String tempLine = null; try { URL address_url = new URL(url); connection = (HttpURLConnection) address_url.openConnection(); connection.setRequestMethod("POST"); connection.setDoOutput(true); connection.setDoInput(true); connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("Accept-Charset", "utf-8"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setRequestProperty("Content-Length", String.valueOf(parameterData.length())); //設置訪問超時時間及讀取網頁流的超市時間,毫秒值 System.setProperty("sun.net.client.defaultConnectTimeout","3000"); System.setProperty("sun.net.client.defaultReadTimeout", "3000"); outputStream = connection.getOutputStream(); outputStreamWriter = new OutputStreamWriter(outputStream); outputStreamWriter.write(parameterData); outputStreamWriter.flush(); if (connection.getResponseCode() >= 300) { throw new Exception("HTTP Request is not success, Response code is " + connection.getResponseCode()); } inputStream = connection.getInputStream(); inputStreamReader = new InputStreamReader(inputStream); reader = new BufferedReader(inputStreamReader); while ((tempLine = reader.readLine()) != null) { resultBuffer.append(tempLine); } }finally { if(connection !=null){ connection.disconnect(); } } return resultBuffer.toString(); } }
我所理解的接口自動化測試就是能一次性執行上述編寫的全部測試類的測試方法,如此能夠經過以下方法實現:
在cn.cstor.wwy.test包中新建JUnit Test Suite,名稱爲TestAll
import junit.framework.Test; import junit.framework.TestSuite; public class TestAll { public static Test suite() { TestSuite suite = new TestSuite(AllTests.class.getName()); //$JUnit-BEGIN$ //$JUnit-END$ return suite; } }
在中間加入全部的測試類,這樣執行TestAll.java就能執行全部接口的測試用例
package cn.cstor.wwy.test; import junit.framework.Test; import junit.framework.TestSuite; public class TestAll { public static Test suite() { TestSuite suite = new TestSuite(TestAll.class.getName()); suite.addTestSuite(TestGetAllAppDevices.class); suite.addTestSuite(TestCreateTable.class); suite.addTestSuite(TestGetTableInfo.class); suite.addTestSuite(TestAddTableColumns.class); suite.addTestSuite(TestAddTableRows.class); suite.addTestSuite(TestDeleteTableRows.class); suite.addTestSuite(TestGetTableRowsByDeveApi.class); suite.addTestSuite(TestGetTableRowsByBaseApi.class); suite.addTestSuite(TestGetAllTableInfo.class); suite.addTestSuite(TestGetTopOneResult.class); suite.addTestSuite(TestGetTableRowsByRange.class); suite.addTestSuite(TestGetTableRowsByPKRange.class); suite.addTestSuite(TestGetTableRowsByNewPageCondition.class); suite.addTestSuite(TestDeleteTable.class); suite.addTestSuite(TestAddDevice.class); suite.addTestSuite(TestGetDeviceTopOneResult.class); suite.addTestSuite(TestGetDevsStatisticWithTimeDivision.class); suite.addTestSuite(TestGetHardWareStatisticWithTimeDivision.class); // suite.addTestSuite(TestGetQueryResult.class); suite.addTestSuite(TestGetServerCurrentTime.class); suite.addTestSuite(TestGetStatisticByColumn.class); suite.addTestSuite(TestGetTableRowsByPage.class); suite.addTestSuite(TestQueryDeviceDataAvgValues.class); suite.addTestSuite(TestQueryLongitudeLatitude.class); return suite; } }
@BeforeClass 在測試類被調用前執行,一個測試類中聲明一次,執行一次
@AfterClass 在測試類調用結束後執行,一個測試類中聲明一次,執行一次
@Before 在每一個@Test(測試方法)調用前執行 //Junit3中的setup方法
@After 在每一個@Test調用後執行 //Junit3中的teardown方法
@Test 使用此註解的方法是一個單元測試用例
@Ignore 暫時不執行的測試方法
@Test(timeout = 2000) //用例執行時間不能超過2s
@Test(expected = ArithmeticException.class) //此方法執行後,必須拋出ArithmeticException才能認爲測試執行成功
assert //包含此關鍵字的爲斷言方法
使用TestNG須要在eclipse中安裝TestNG插件
在eclipse界面選擇「Help」–「install New Software」,選擇【Add】,在location中輸入http://beust.com/eclipse,選擇TestNG,點擊【Next】,開始下載安裝。安裝完成後,選擇「Build Path」「Configure Build Path」,在「Task Repository」下有「TestNG」標籤。安裝成功。(此方法若是eclipse版本或者之前是否安裝卸載過的不一樣會形成此方法成功率很小);
在eclipse界面選擇「Help」–「Eclipse Marketplace」中進行查找TestNG 而後進「install」 。(此方法最簡便,力薦。);
TestNG須要使用testng.xml配置層級結構
一、TestSuite由一個或多個Test組成
二、Test由一個或多個測試Class組成
三、一個測試Class由一個或多個測試方法組成
<suite>
<test>
<classes>
<method> </method> </classes> </test> ...... </suite>
TestNG經常使用註解
@BeforeSuite //在當前測試集合的任意測試用例開始前執行
@AfterSuite //在當前測試集合的因此測試用例結束後執行
@BeforeTest //……
@AfterTest
@BeforeGroups
@AfterGroups
@BeforeClass
@AfterClass
@BeforeMethod
@AfterMethod
@Test
給測試方法分組
@Test (groups = {「xx1」}) @Test (groups = {「xx2」})
調用單個分組testng.xml
<suite name="suitetest"> <test name="test"> <groups> <run> <include name="xx1"/> </run> </groups> <classes> <class name="pp.com.TestClass1"/> <class name="pp.com.TestClass2"/> </classes> </test> </suite>
調用多個分組testng.xml
<groups> <define name="All"> <include name="xx1"> <include name="xx2"> </define> <run> <include name="xx1"/> </run> </groups>
依賴測試
@Test (dependsOnMethods = {「testMethod2」}) //能夠保證先執行testMethod2再執行該方法
特定順序執行測試用例
@Test (priority = 1) //priority從0開始,0優先級最高
跳過摸個測試方法
@Test (priority = 1,enabled=false)
測試報告中的自定義日誌
方法中增長 Reporter.log(「打印日誌」) 打印出來的日誌會在TestNG測試報告中
@Parameters(「browser」) 定義browser參數,在測試執行過程當中,此參數的具體值由testng.xml中的
<parameter name="browser" value="firefox"/>
配置來傳遞給測試程序
參考:https://blog.csdn.net/wanglha/article/details/50331577
https://testerhome.com/topics/10525
https://blog.csdn.net/do_your_self_thing/article/details/6247834