自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

【NCTS峰會回顧】汽車之家聞小龍:QA團隊精準測試實踐之路

開發(fā) 前端
2019年10月26日,由Testin主辦的第二屆NCTS中國云測試行業(yè)峰會在京召開,此次峰會以“AI+未來”為主題,匯聚來自國內(nèi)外測試領域的知名專家學者、領先企業(yè)決策者、高層技術管理者、媒體從業(yè)者等,共同探討高端云測試技術。

2019年10月26日,由Testin主辦的第二屆NCTS中國云測試行業(yè)峰會在京召開,此次峰會以“AI+未來”為主題,匯聚來自國內(nèi)外測試領域的知名專家學者、領先企業(yè)決策者、高層技術管理者、媒體從業(yè)者等,共同探討高端云測試技術,幫助測試從業(yè)者了解最前沿行業(yè)趨勢,及最新的行業(yè)實踐。

[[284799]]

會上,汽車之家新車電商事業(yè)部高級測試工程師聞小龍做《QA團隊精準測試實踐之路》主題演講。聞小龍指出,“自動化測試本質(zhì)上是根據(jù)測試的設計去執(zhí)行的,只是執(zhí)行手段不一樣,當設計出了問題,自動化測試不管再怎么執(zhí)行還是會遺漏那個問題,所以,自動化測試沒有解決所有的問題。”

以下為聞小龍演講實錄:

我是汽車之家電商事業(yè)部的聞小龍,今天很高興給大家進行分享,我想先做一個現(xiàn)場調(diào)查,在座各位多數(shù)工作是功能測試相關的?還是很多的!我也是一名一線測試人員,所以我今天講的內(nèi)容可能大家會比較感同身受。

我們組內(nèi)每隔一段時間聚在一起聊聊最近工作的問題和可以改進的地方,時間長了,我們發(fā)現(xiàn)問題是多種多樣的,但抽象出來后最主要的矛盾大概有那么兩個。

一、測試深度、廣度,與測試資源、項目時間的矛盾。

二、被測系統(tǒng)的黑盒狀態(tài)與需要了解系統(tǒng)的矛盾。

發(fā)現(xiàn)矛盾以后我們進行了思考,下面我想說一下整個思考的過程,并且這個過程我想通過一個比較有意思的方式去跟大家交流。

前一段時間我發(fā)現(xiàn)一個游戲,這個游戲在朋友圈流行過一段時間,相信很多人也都玩過,規(guī)則很簡單,你需要在規(guī)定時間內(nèi)找出跟周圍色塊不一樣的色塊,左邊圖是第一關的截圖,大家很容易看到右下角色塊會淺一些,點擊它,這關就成功了。當玩兒到55關的時候,大家還能一眼找到不同的色塊嗎?

還是有一些難度的是吧,所以我覺得我死在這關不是特別冤,當色塊不斷增加你會發(fā)現(xiàn)難度是會遞增的,我覺得這個東西特別像我們的測試,為什么這樣說呢?大家都寫過用例,用例設計是把不同邏輯分支進行組合,最后會羅列出來數(shù)量比較大邏輯路徑,測試工作的本質(zhì)是什么?我們對所有路徑進行覆蓋,然后找出其中有問題的幾個路徑,舉個例子,比如:訂單系統(tǒng)的測試,訂單類型其實就有很多,再加上不同平臺下PC端,APP端;還需要考慮中間的操作差異,比如說我加到購物車里下單,還是直接下單,考慮完這些影響因素以后,按照我們用例設計方法正交分析法進行分析,很簡單的一個下單場景,我發(fā)現(xiàn)有102種路徑組合。          

假如說我們訂單系統(tǒng)修改了其中一個路徑,要完整回歸102種下單情況,才能覆蓋所有的邏輯。我們發(fā)現(xiàn)這個成本在我們敏捷開發(fā)和快速迭代當中是一個很大的瓶頸。

我們要去解決這個問題,第一個想到的就是減少工作量,還是從游戲說起,既然這一關難以完成,并且我們分析了造成難度的是色塊數(shù)量過多,我們有沒有什么方法把色塊減少呢?如果我們能把色塊減少是不是意味著回到了前面的關卡,所以你就能快速的把問題色塊找出來。映射到測試,每個團隊都有經(jīng)驗豐富的員工,會根據(jù)這次改動告訴你其實有一些訂單類型是不用回歸的,因為這些跟你的改動點關系比較弱,所以說我們不用測;然后會告訴你這個邏輯的改動點,和他是否加入購物車其實感覺上關系不大,所以直接測直接下單就可以包含所有場景。

當我們把經(jīng)驗者建議的影響因素刨除后,我們發(fā)現(xiàn)場景確實大大減少了,但是長時間按照這種思路實施以后,你會發(fā)現(xiàn)你還是偶爾的遇到一些線上的問題,你拿出來復盤分析的時候會發(fā)現(xiàn)你排除掉的路徑出了問題。為什么會出現(xiàn)這個問題?分析到最后發(fā)現(xiàn)是因為這種經(jīng)驗性的進行測試范圍的縮減是沒有依據(jù)的,當你把你的可能發(fā)現(xiàn)問題的路徑排除在計劃之外的時候,不管執(zhí)行做的再仔細,其實在計劃階段你已經(jīng)失去了發(fā)現(xiàn)它的可能性。

我們測試人員真的沒有辦法搞定這個問題么?這時候就有人會說既然質(zhì)量保證是我們天職,那我們還是需要投入足夠的資源和時間把所有路徑都回歸完,起碼能夠保證系統(tǒng)的穩(wěn)定性。但是說這句話的同學忽略了一個問題,游戲的右上角是有時間的,游戲規(guī)則不允許你隨意的拉長單局時間,就像你老板跑過來質(zhì)問你,為什么我給了你這么多人,卻沒有達到快速迭代的效果一樣。

這時候我們就想,難道我們就沒有一個好方法了嗎?當然不是。依據(jù)大家玩游戲的經(jīng)驗,你想快速而顯著的提高游戲能力,其實很簡單,那就是充錢買道具?,F(xiàn)在大家看到的就是我們的第一個道具:自動化測試,這也是我們的第一個想法,既然你工作量過大,那我也不去想怎么減少你的工作量,我用一個更直接粗暴的辦法,使用工具遍歷所有路徑,大家都知道自動化測試執(zhí)行成本是不高的對吧,它能在瞬間完成海量的路徑覆蓋,這是一個優(yōu)點。但是自動化測試真的一勞永逸么?從很久之前行業(yè)就存在了很多的自動化解決方案,當然我們也不能免俗,不管是UI、API的我們都做了大量嘗試,但是真的實踐過程當中我們發(fā)現(xiàn)自動化這個道具還是存在一些問題的。

自動化測試并不是憑空而生,每一次需求進行到開發(fā)提測階段,進行腳本編寫的時候其實是一個很大的成本。有的同學會說,腳本編寫是一次性成本,可能第二次回歸時候你去用它就沒有這部分的成本了,但是你真的在做時候就會發(fā)現(xiàn),當項目進行快速迭代時,第一個版本寫好的腳本往往到了下一個版本就跑不通了,所以又需要你去付出一些維護成本。

自動化測試還有一個問題,它在一些技術棧當中不能保證所有地方都能覆蓋到,有一些不能覆蓋的地方,我們通常會在自動化測試測后增加手工檢查,因為人的靈活性還是有巨大優(yōu)勢的。但是這里有一個問題,自動化測試跑完以后移交給手工人員,但當功能總量很大的時候,你發(fā)現(xiàn)你已經(jīng)無法特別精準的描述你需要補充的地方了,所以手工測試人員就不能有的放矢,被迫按照自己的方式做盡量多的覆蓋,這樣會在測試過程中重新引入主觀因素,最后無法避免的造成漏測。

另一方面,還記得前面咱們說過的盲目測試范圍縮減會造成漏測的問題么,其實自動化測試也會遇到這個問題,因自動化測試本質(zhì)上是根據(jù)測試的設計去執(zhí)行的,只是執(zhí)行手段不一樣,當設計出了問題,自動化測試不管再怎么執(zhí)行還是會遺漏那個問題,所以,自動化測試并沒有解決所有的問題。

我們發(fā)現(xiàn),原來自動化測試有這么多不盡如人意的地方,這個道具有一些缺陷,那我們是不是該尋找一些新的道具呢?我們先不揭曉有哪些新道具,我們分析一下我們到底需要些什么?

還記得我們開始說的兩個主要矛盾么,第一個矛盾其實就是工作量與資源時間的矛盾,那我們最需要一個工具去指引我們縮小工作量,但是這個縮小要是有依據(jù)的,我們需要的這個范圍,一定是可以找出所有問題的,這是我們想要的第一個道具。

如果還可以擁有一個道具,我們可以順著后面自動化的思路來想,自動化是一定要做的,但是自動化中主要的問題需要第二個道具來彌補,這個工具可以告訴我們一個自動化明確的邊界,它可以是一個可視化顯示,告訴手工人員需要對哪些東西進行補測。

我們既然有了這些愿景,我們就進行了一些調(diào)查和思考,我們發(fā)現(xiàn),第一個縮小測試范圍的功能需要在代碼維度入手,通過開發(fā)每次提交的代碼差異去分析我們需要測試的范圍,我們拿到代碼變動去分析測試范圍,這就把分析過程做到了有據(jù)可依,這也解決了我們開頭提到的對系統(tǒng)了解不足的矛盾。

第二個工具是對測試過程進行可視化反饋,這個東西就是代碼覆蓋率監(jiān)控,不管是自動化測試還是手工測試,最后都會得到一個可視化的測試報告,就是哪些邏輯跑過了,哪些邏輯還沒有跑。

有了這兩個理論基礎后,我們查找可復用的技術棧時發(fā)現(xiàn)已經(jīng)有了一些比較好的開源工具,我們將這些開源軟件進行二次開發(fā),加上自研的DIFF引擎,可以達到我們的預期想法,我們依據(jù)這些思路對系統(tǒng)進行了實現(xiàn)

下面這一部分是工具在我們項目當中跑起來以后,過程中的一些實踐和收益情況,下面我們大家一起看一下。

首先簡單說一下實現(xiàn)思路和使用的技術棧,首先我們代碼管理托管在私有的gitlab上,首先我們通過Git Diff命令獲取代碼差異,當開發(fā)修改了代碼提交版本后,我們用這個版本和上一個版本進行DIFF,差異信息會告訴你某一段代碼哪幾行發(fā)生了改變。我們通過一些字符處理方式,把這個處理成通用的Json格式的數(shù)據(jù),格式大致為某一個JAVA類中哪些行發(fā)生了改變。我們分析數(shù)據(jù)發(fā)現(xiàn)這不是我們想要的。因為行沒有很好的含義性,我們發(fā)現(xiàn)方法是很好的入口,因為一個方法是一個動作,我們其實想知道的是哪些動作發(fā)生了變化,然后進行針對性測試。所以我們需要對它進行轉化,在轉化的過程中用到了AST(抽象語法樹),抽象語法樹的簡稱是AST,這是一個可以把靜態(tài)代碼實例化成樹狀結構的工具,這個樹狀結構的每一個節(jié)點都是一個語法結構,方法,行,甚至注解都是語法樹的一個節(jié)點。都可以方便的進行分析和處理,我們通過語法樹可以拿到每一個方法行范圍,大家知道上一步已經(jīng)拿到了差異行號,我們用差異行號去命中所有的方法,當一個行號命中了一個方法,我們把這個方法進行標記,最后我們得到了差異的方法列表,方法是動作,因此,我們知道了哪些動作發(fā)生了代碼變動,我們需要對這些動作進行覆蓋。

看架構圖中的紅線,是方法的差異列表,我們把數(shù)據(jù)引出來,然后我們灌到覆蓋率監(jiān)控里,就會得到基于代碼變動的覆蓋率監(jiān)控報告。

Jacoco大家如果關注過覆蓋率監(jiān)控,應該都聽說過,是JAVA語言里的一個覆蓋率監(jiān)控開源工具,我們對源碼進行了二次開發(fā),并與代碼差異分析數(shù)據(jù)結合,下面講述這兩者是如何進行融合的。

首先我們需要簡單說一下Jacoco的工作原理,首先Jacoco分為兩部分,第一部分是插樁部分,對被測服務進行插裝操作,其實就是在每一個邏輯分支插一個探針,當邏輯分支被執(zhí)行了,探針會變成True,未被執(zhí)行會保持初始的fals,最后通過探針數(shù)據(jù)我們就能得到哪些邏輯被執(zhí)行過了,而哪些邏輯未被執(zhí)行,

下面我們來說Jacoco的第二部分,命令部分,我們可以通過一個jacoco的dump命令遠程獲取這些探針數(shù)據(jù)。

第二個是merge命令,其實是將多次拿到的探針數(shù)據(jù)進行合并操作,這個解決了什么問題呢?舉個例子當被測服務多次重啟,但是重啟前做的覆蓋數(shù)據(jù)如果不想丟掉,就需要將它合并到一起,這樣能夠保證探針數(shù)據(jù)的完整性,當你拿到完整覆蓋率數(shù)據(jù)以后,最后一步是report命令,這個命令是把覆蓋率數(shù)據(jù)形成一份可視化報告,告訴你整個的項目有多少被覆蓋。

接下來就是代碼差異信息的引入,我們?nèi)胧贮c是在可視化的時候做一個過濾,當執(zhí)行report命令時,會有一個遍歷所有方法生成報告的邏輯,我們會在這個遍歷的過程中判斷當前方法是否發(fā)生改變,如果沒有改變我們就剔除掉,最后得到的就是我們需要測試部分的報告了。

我們的本意是想通過工具幫助測試人員更好完成測試工作,但是我們不想增加額外成本,所以我們把上面部分功能進行模塊化拆分,每一步可能是一個命令,一個接口,可以嵌入到CI的過程當中,我們開始嵌入到Jenkins,后來又對接了集團的云平臺,因為我們將功能進行了服務化,可以很方便的和外部系統(tǒng)進行對接。

下面跟大家交流一下工具在我們測試工作當中的一些應用情況,下面是一個示例,某天下午我收到的開發(fā)的提測,他告訴我這個需求已經(jīng)部署到測試環(huán)境,我可以進行測試了。

我們先來說說這個需求的背景,我們是做汽車電商的部門,基本業(yè)務形態(tài)是可以在網(wǎng)上買一些汽車相關的產(chǎn)品,比如買一個汽車的抵扣券,你花100塊錢買一個2千塊錢抵扣券,你出示券碼可以在總車款抵扣兩千塊錢,就像之前團購的餐券線上購買線下消費。

但是汽車電商略有不同,因為它還需要支付大額的尾款,比如說支付20萬尾款,這個支付過程時間有可能會比較長,比如有些顧客需要刷好幾張卡,如果其中一個卡出問題還需要解決一下,所以支付系統(tǒng)給我們提了一個需求,需要在他刷第一筆款時把券碼鎖住,避免打款過程中,券碼狀態(tài)發(fā)生改變。

這是他大體的需求,從技術維度來講需要我們提供一個接口,我們對接口進行測試,按照常規(guī)測試,與開發(fā)聊很多開發(fā)的設計和我們需要測試的東西,既然是要試用新工具,那我決定這次換一個方式開始這個任務,我沒有找開發(fā)直接聊,而是拉了項目覆蓋率報告,我們發(fā)現(xiàn)都是紅色的,這代表什么?代表著這個分支沒有被測試過,因為還沒有進行測試。

第二個現(xiàn)象是這個項目的覆蓋率報告只有一個類被顯示了出來,這說明開發(fā)只修改了這一個類,所以我的測試范圍就被控制在了這一個類以內(nèi),這就達到了縮小測試范圍的目的。然后我們再去分析改的這部分代碼,我們發(fā)現(xiàn)這就是是一個spring MVC編寫的接口的代碼,前面是各種參數(shù)校驗,后面是對券碼的操作邏輯。

我們先進行冒煙測試,就是拿開發(fā)給我們一個URL 和demo參數(shù)進行調(diào)用,我們將接口測試的數(shù)據(jù)錄入我們自研的接口測試平臺并運行,發(fā)現(xiàn)接口給我反饋了錯誤代碼4207(提車碼不正確)-不可凍結。按照之前的方法我們會直接扔給開發(fā)讓他們查找原因,現(xiàn)在我們換了一個方式,我們沒有直接扔給開發(fā),而是拉了一次覆蓋率報告,報告中綠色代表的是被執(zhí)行,黃色代表部分被執(zhí)行。我們發(fā)現(xiàn)邏輯已經(jīng)進入了這個方法,然后在第三個IF判斷時候進入了報錯邏輯,并拋回了錯誤信息,這個過程有一點像開發(fā)的Debug,我們看語句塊進入邏輯,發(fā)現(xiàn)是券碼狀態(tài)有問題,我推斷可能開發(fā)給我測試數(shù)據(jù)時候,可能已經(jīng)用這個參數(shù)進行了自測,已經(jīng)變成凍結狀態(tài)了,我再次凍結自然可能就有問題了,我分析出問題的原因,其實問題已經(jīng)解決一大半了,怎么解決呢,因為我們還有解凍接口,我用同樣的參數(shù)調(diào)用了解凍接口,我發(fā)現(xiàn)成功了,說明我們的推斷是正確的。

我們繼續(xù)驗證,我再次調(diào)用凍結接口,我發(fā)現(xiàn)這次凍結成功了,發(fā)現(xiàn)我們的推斷是完全正確的。

我們再拉一下覆蓋率數(shù)據(jù),我們發(fā)現(xiàn)已經(jīng)跳出了上一次把我們?nèi)映鋈サ倪壿?,然后進行到底部也就是主邏輯,我們發(fā)現(xiàn)這個方法完全被執(zhí)行了,這個節(jié)點在測試中其實很重要,叫做主流程跑通。有些質(zhì)量要求級別低的項目主流程跑通是可以上線的。

但是我們這時候拉取了整個項目覆蓋率情況,我們發(fā)現(xiàn)只有62%,我主流程跑通了,但是覆蓋率只有一半多一點,這個數(shù)據(jù)當然不是很理想,沒有關系,我們進一步去分析原因,我們需要分析的是里面的紅色部分,我們發(fā)現(xiàn)紅色部分都是異常情況的判斷,說第一個校驗的是參數(shù)合法性,這段邏輯無法進入是因為我們參數(shù)合法的,我要進去很簡單,我將參數(shù)改成非法就可以了,所以我把其中一個參數(shù)APPID改為不合法,然后再去調(diào)用,我發(fā)現(xiàn)有一些不同,給我返回了一個類似Json的信息,但是內(nèi)部是空白的,這應該是有問題的,因為一個接口可以返回正確也可以返回錯誤,但是返回空白一定是不正確的,所以我就把問題反饋給開發(fā),開發(fā)直接問我哪一個方法你知道嗎,我直接把方法貼給對方,因為我跟進覆蓋率報告,分析的就是代碼級別的東西,所以他根據(jù)你貼的代碼,就不需要調(diào)試直接就定位到問題了,然后修復了該問題。

我們再次用同樣的參數(shù)組合調(diào)用了一下凍結接口,發(fā)現(xiàn)反饋給了我們想要的東西,同時開發(fā)也表達了他比較激動的心情。為什么會這樣?因為你給他減少了工作量,他不需要去調(diào)試,不需要重復做你做過的事情了,所以代碼級別的一個溝通就會給他省掉很多工作量。

我們?nèi)绶ㄅ谥?,把所有代碼塊都進行了條件分析,對它進行進入測試。

這個校驗的是提車碼不存在的情況,我們把提車碼改成不存在的場景也進入了。這個校驗的是提車碼的有效期,我們把時間改成過期也可以進入這個邏輯。

其實操作都差不多,就是根據(jù)它的條件進入反面的邏輯就能進入到相關邏輯,這是一個信息的狀態(tài),這是訂單類型,我們改成非法類型也可以進入,非法校驗確實很多。當我們把所有非法校驗進行了一個測試以后,我們這時候拉取覆蓋率報告,發(fā)現(xiàn)基本上全變成綠色了,因為所有邏輯我們都進行了覆蓋,下面僅有兩行紅色,我們發(fā)現(xiàn)其實是一個異常捕獲,就是當你邏輯進行不可預知異常才會進入,這是一個破壞性測試,比如中間掉一個接口報錯了,然后我們就會進入這個異常捕獲,理論上也可以進入的。

這時候我們再拉一次項目級別覆蓋率數(shù)據(jù),我們發(fā)現(xiàn)自解碼已經(jīng)到97%,分支已經(jīng)到83%,我們認為這還是不錯的覆蓋率數(shù)據(jù),并且紅色部分我們也進行了合理化解釋,所以我們覺得這是比較理想的測試結果。

我們復盤一下這個過程,這個工具到底幫助我們提升了什么?首先我前面故意找了一個我不是很熟悉的隔壁組項目來做的。開發(fā)只給了我一個URL和Demo參數(shù),我發(fā)現(xiàn)我最后得到了一份很豐富的測試用例,我跟測試人員聊了,其實真的是按照傳統(tǒng)方式測的話可能其中很多的前置條件還會漏掉,一些異常情況會進入不了。

所以第一個收益是在我不了解一個業(yè)務邏輯情況下我完成了測試,并且這個測試是相對全面的。

第二個收益是我在前面測試所有參數(shù)組合都錄入到我們系統(tǒng)當中,當我需要回歸這個接口的時候可能只需要運行上面錄得所有接口參數(shù)組合就可以了,但是這里我想說的并不是自動化測試,當你多次迭代后,如果你自動化測試沒有進行及時的更新,那自動化測試的效果就會越來越差,這時你就會發(fā)現(xiàn)自動化的測試的作用會被逐漸消磨掉,我們發(fā)現(xiàn)覆蓋率監(jiān)控可以解決這個問題,我們每次執(zhí)行自動化測試都會關注它的覆蓋率。假如說這一次是98%,下次執(zhí)行是我發(fā)現(xiàn)覆蓋率變成了60%,一定是開發(fā)加了新邏輯,而你的自動化測試沒有更新,那就需要你對自動化用例進行更新了,所以等于我們加入了一個自動化測試用例效果的監(jiān)控機制。

再說第三個收益,我們在整個用例設計過程當中是有依據(jù)的,我們不會隨意的刪減有效用例,也不會做一些多余的無效覆蓋,我們把這叫做精準化測試思想,大家可以看到精準化測試思路在我們測試流程當中,對我們的幫助是多方面的。

再來說說我們的愿景,我們更深層次的復盤了我們的整個流程,發(fā)現(xiàn)中間這個工具只是幫助我們?nèi)シ治隽艘恍〇|西,但是具體分析和操作還是需要人力去完成的,我們就在想其中一些工作量是不是還可以繼續(xù)交給工具。我們既然拿到操作覆蓋率,我們反過來想我們是不是能夠建立代碼節(jié)點與用例集、用例組的關系,就是當代碼改變時候我可以映射出我需要執(zhí)行的哪些用例。當我們采集到這個關系以后,我們用DIFF引擎把差異代碼分析出來,我們直接映射到的就是我們用例級別的測試方案了。

大家會覺得有一點天方夜譚,我們開始也這么想,因為等于把測試策略交給機器去做,我們對這個方案也是充滿了顧慮,所以我們加了圖中最下面這一行,我們把推薦的用例執(zhí)行過程進行監(jiān)控,并根據(jù)監(jiān)控結果回過頭來查找推薦本身是否存在缺陷,假如說缺陷是用例不完整造成的,那我們就補充用例,如果關系有問題我們就進行關系調(diào)優(yōu),最終形成一個自我優(yōu)化的閉環(huán)。

以上就是我所有分享內(nèi)容,謝謝大家!

 

責任編輯:張燕妮 來源: 51CTO
相關推薦

2019-12-05 16:23:15

開發(fā)技能代碼

2019-12-13 11:58:21

AI 數(shù)據(jù)人工智能

2019-12-05 16:01:24

云計算行業(yè)科技

2019-11-26 17:52:18

AI 數(shù)據(jù)人工智能

2019-11-26 18:00:59

系統(tǒng)運維架構

2023-06-27 07:26:36

汽車之家敏感數(shù)據(jù)治理

2023-07-24 09:03:38

汽車之家頁面性能監(jiān)控

2019-11-26 17:44:16

AI 數(shù)據(jù)人工智能

2019-12-05 16:25:26

開發(fā)技能代碼

2019-11-26 17:38:15

人工智能AI開發(fā)者

2019-12-13 11:51:34

技術AI云計算

2023-04-28 07:41:38

Unity前端架構

2019-12-05 16:15:32

云計算行業(yè)科技

2019-11-26 17:58:47

系統(tǒng)運維架構

2022-08-31 07:54:08

采集sdk埋點數(shù)據(jù)

2019-11-26 17:56:21

開發(fā)AI360搜索

2019-11-26 17:41:59

AI 數(shù)據(jù)人工智能

2019-12-13 11:55:30

AI 數(shù)據(jù)人工智能

2019-12-13 11:54:06

AI 數(shù)據(jù)人工智能

2015-04-16 13:34:56

點贊
收藏

51CTO技術棧公眾號