項目實踐之java調用python


 

背景:在進行javaweb項目開發時,通過登錄設備,調用不同的測試用例(對設備下發命令,獲取回顯信息),判斷業務是否達到預期效果。利用python的telnet模塊進行實現較為方便,具體實踐時也遇到一系列問題,主要包括:(1)java調用python的參數傳遞與實時回顯問題; (2)python日志模塊的重復打印問題

1 java調用python

關於java調用python的方法,常見的有2種。第一種:使用java的Process類調用python腳本,然后讀取回顯信息,此方法的缺點是對於python的回顯信息反應較慢,無法滿足實時回顯需求。

第二種方法,利用Jython執行python方法,優點:能獲取python方法的返回值,作為java調用python其他方法的入參,較好地控制代碼流程,能更好的滿足項目需求,同時,它能及時的獲取python方法的返回值,因此,強力推薦該方法。

第一種方法代碼如下:

 1  public static void main(String[] args)
 2     {
 3         // 1. 根據用戶輸入設備信息、選擇用例修改腳本
 4         String shellPath = "D:\\dDevelopemnt\\javaDemo\\project1\\clockDetect\\src";
 5 
 6         Runtime run = Runtime.getRuntime();
 7 
 8         // 2. 執行cmd
 9         try
10         {
11             // run.exec("cmd /k shutdown -s -t 3600");
12             // cmd.exe /k
13 
14             Process process = run.exec(" cmd /c D: && cd " + shellPath + " && python clkChecker.py fdas fda 432");
15 
16             InputStream input = process.getInputStream();
17             BufferedReader reader = new BufferedReader(new InputStreamReader(input, Charset.forName("GBK")));
18             String szline;
19             System.out.println("\n********** DOS info begin **********");
20             while ((szline = reader.readLine()) != null)
21             {
22                 System.out.println(szline);
23             }
24             System.out.println("********** DOS info end **********\n");
25 
26             // 第四步:輸出Log,移動到指定路徑
27 
28             reader.close();
29             process.waitFor();
30             process.destroy();
31         }
32         catch (Exception e)
33         {
34             e.printStackTrace();
35         }
36     }
View Code

第二種方法代碼如下:

java側代碼

 1 public void exeTestCases(
 2             ArrayList<String> lstCaseNames,
 3             String projectName,
 4 
 5             String deviceAip,
 6             String deviceAport,
 7             String deviceAusername,
 8             String deviceApasswd,
 9 
10             String deviceBip,
11             String deviceBport,
12             String deviceBusername,
13             String deviceBpasswd){
14 
15         String shellPath = "D:\\dDevelopemnt\\javaDemo\\project1\\clockDetect\\src\\clkJython.py";
16 
17         Properties props = new Properties();
18         props.put("python.console.encoding", "UTF-8"); // Used to prevent: console: Failed to install '': java.nio.charset.UnsupportedCharsetException: cp0.
19         props.put("python.security.respectJavaAccessibility", "false"); //don't respect java accessibility, so that we can access protected members on subclasses
20         props.put("python.import.site","false");
21         Properties preprops = System.getProperties();
22         PythonInterpreter.initialize(preprops, props, new String[0]);
23         PythonInterpreter interpreter = new PythonInterpreter();
24         interpreter.exec("import sys");
25         interpreter.exec("sys.path.append('D:\\dDevelopemnt\\javaDemo\\project1\\clockDetect\\src')");//自定義庫函數路徑
26         interpreter.execfile(shellPath);
27 
28         // 前端設備信息封裝
29         JSONObject jsondata = new JSONObject();
30         jsondata.put("\"projectName\"","\""+projectName+"\"");
31         jsondata.put("\"deviceAip\"","\""+deviceAip+"\"");
32         jsondata.put("\"deviceAusername\"","\""+deviceAusername+"\"");
33         jsondata.put("\"deviceApasswd\"","\""+deviceApasswd+"\"");
34         jsondata.put("\"deviceAport\"","\""+deviceAport+"\"");
35         jsondata.put("\"deviceBip\"","\""+deviceBip+"\"");
36         jsondata.put("\"deviceBusername\"","\""+deviceBusername+"\"");
37         jsondata.put("\"deviceBpasswd\"","\""+deviceBpasswd+"\"");
38         jsondata.put("\"deviceBport\"","\""+deviceBport+"\"");
39         jsondata.put("\"lstCaseNames\"","\""+lstCaseNames+"\"");
40 
41         System.out.println(jsondata.toString());
42 
43         // 調用Python方法傳遞參數、返回參數
44         // 第一個參數為期望獲得的函數(變量)的名字,第二個參數為期望返回的對象類型
45         PyFunction pyFunction = interpreter.get("setConfig", PyFunction.class);  // 1.前端傳遞設備類表及參數信息
46 
47         //調用函數,如果函數需要參數,在Java中必須先將參數轉化為對應的“Python類型”
48         PyObject pyobjDictInfo = pyFunction.__call__(new PyString(jsondata.toString())); // 2.返回Python側封裝的設備信息
49 
50         // 前端選取的測試用例
51         for(String item:lstCaseNames){
52             System.out.println("-----"+item+"------");
53             PyFunction fun1 = interpreter.get(item, PyFunction.class);         // 3.調用執行用例1
54             PyObject pyobjDictSync = fun1.__call__(pyobjDictInfo);                     // 4. 獲取執行用例1的結果
55             System.out.println("****"+item+" now exe finished! "+ item  + new Date().toString() );
56 
57             // 將消息推送至客戶端,告知釋放的設備ip
58             try {
59                 WebSocketServer.sendInfo(pyobjDictSync.toString());
60             } catch (IOException e) {
61                 e.printStackTrace();
62             }
63         }
64 
65 
66     }
View Code

上述29-39行是java側封裝成標准json格式數據

44-48行是java側調用python方法,進行設備的登錄,涉及項目進行參數的配置(設備用戶名、密碼、ip、項目名稱等入參)

pyobjDictInfo是python側封裝的字典數據,包括設備列表以及Telnet對象等,該參數作為執行測試用例的入參,

51-63行是遍歷測試用例

python側代碼 

 1 '''
 2           通過Jython調用
 3 '''
 4 def setConfig(data):
 5     res= json.loads(data) # 根據字符串書寫格式,將字符串自動轉換成 字典類型
 6     
 7     global projectName
 8     projectName =  eval(res['"projectName"'])    
 9     logDir = "d:\\loggg\\" + projectName+"_log.txt"
10     
11     # 創建一個logger
12     global root_logger
13     global fh
14     global ch
15     
16     root_logger = logging.getLogger("clkLogger")
17     root_logger.setLevel(logging.DEBUG)
18     
19     # 創建一個handler,用於寫入日志文件
20     fh = logging.FileHandler(logDir)
21     fh.setLevel(logging.DEBUG)
22     
23     # 再創建一個handler,用於輸出到控制台
24     ch = logging.StreamHandler()
25     ch.setLevel(logging.DEBUG)
26     
27     # 定義handler的輸出格式
28     formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
29     fh.setFormatter(formatter)
30     ch.setFormatter(formatter)
31     
32     # 給logger添加handler
33     root_logger.addHandler(fh)
34     root_logger.addHandler(ch)    
35     logger = root_logger; # 修改全局日志變量
36     
37     logger.info("======================================== project "+projectName+" begin ========================================")
38     logger.debug(res)
39     
40     dictDevice = {}
41     dictDevice['key1'] = [eval(res['"deviceAip"']) , eval(res['"deviceAusername"']),eval( res['"deviceApasswd"']), eval(res['"deviceAport"'])]
42     dictDevice['key2'] = [eval(res['"deviceBip"']), eval(res['"deviceBusername"']), eval(res['"deviceBpasswd"']), eval(res['"deviceBport"']) ]
43     
44     logger.info("==================== login device begin ====================") 
45     myclass = MyClass();
46     dictInfo = myclass.tearUp(dictDevice)
47     
48     return dictInfo
49 
50 
51 # 測試用例1
52 def checkClk(dictInfo): 
53     logger.info("====================  1.1基本功能  begin ====================") 
54     lstInfo = clearConfigInfo(dictInfo)    
55     dict = detect_clk_sync(lstInfo[0],lstInfo[1],lstInfo[2],lstInfo[3])
56     logger.debug(dict)
57     logger.info("====================  1.1基本功能  end ====================") 
58     return dict
59 
60 # 測試用例2
61 def checkClkfreq(dictInfo):
62     logger.info("====================  1.2測試用例2  begin ====================")
63     lstInfo = clearConfigInfo(dictInfo)    
64     dict = detect_clk_freq_deviation(lstInfo[0],lstInfo[1],lstInfo[2],lstInfo[3])
65     logger.debug(dict)
66     logger.info("====================  1.2測試用例2  end ====================")
67     return dict

 其中,46行處調用函數如下,返回值包含telnet對象

 1     # 登錄設備
 2     def tearUp(self,dictDevice):
 3         dictInfo = {}
 4         
 5         
 6          lstA =  dictDevice['key1']
 7          lstB =  dictDevice['key2']
 8          deviceA = [lstA[0],lstA[1],lstA[2],lstA[3]];
 9          deviceB = [lstB[0],lstB[1],lstB[2],lstB[3]];
10         
11         try:
12             logger.info(deviceA)
13             logger.info(deviceB)
14             
15             telnetA = telnetlib.Telnet(deviceA[0], port=23, timeout=50)
16             loginsys(telnetA,deviceA[1],deviceA[2])
17             # print deviceInfo(telnetA) # 獲取設備信息
18            
19             telnetB = telnetlib.Telnet(deviceB[0], port=23, timeout=50)
20             loginsys(telnetB,deviceB[1],deviceB[2])
21 
22             dictInfo["telnetA"] = telnetA
23             dictInfo["telnetB"] = telnetB
24             dictInfo["deviceA"] = deviceA
25             dictInfo["deviceB"] = deviceB
26             
27             logger.info("------ login success ------")
28             
29         except(SystemExit, KeyboardInterrupt):
30             logger.info("------ ping error ------")
31                         
32         except Exception as e:
33             logger.error("failed to ping", exc_info=True)
34                                 
35         return dictInfo

 

2 日志的重復打印問題

背景:在前端配置頁面,輸入項目項目,后端python解析后,以該項目名稱作為log名稱。

 

 

 因此,在每次點擊“提交”按鈕都會執行python側的setConfig函數,導致日志模塊會不斷添加handler,重復打印日志,

如下圖:

這顯然不利於日志處理,隨着測試項目的不斷增多,重復的次數也會不斷增加。

因此,需要在每次執行完一個項目時,就刪除日志的handler模塊,具體實現函數為

1 '''
2    測試用例執行完畢,調用此方法
3 '''
4 def tear_down():
5     logger.debug("close the logging handlers")
6     root_logger.removeHandler(fh)
7     root_logger.removeHandler(ch)
8     logger.removeHandler(fh)
9     logger.removeHandler(ch)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM