測試對象串行化_第1頁
測試對象串行化_第2頁
測試對象串行化_第3頁
測試對象串行化_第4頁
測試對象串行化_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

第第頁測試對象串行化測試對象串行化

發(fā)表于:2023-05-24來源::點擊數(shù):標(biāo)簽:開發(fā)測試使最杰出串行

即使最杰出的開發(fā)人員有時也會忘記測試對象串行化,但那并不能作為您犯下同一錯誤的借口。在這篇文章中,ElliotteRustyHarold將解釋對對象串行化進行單元測試的重要性,并為您展示一些應(yīng)牢記的測試。測試驅(qū)動的開發(fā)的總體原則之一就是應(yīng)測試一個類已

即使最杰出的開發(fā)人員有時也會忘記(測試)對象串行化,但那并不能作為您犯下同一錯誤的借口。在這篇文章中,ElliotteRustyHarold將解釋對對象串行化進行單元測試的重要性,并為您展示一些應(yīng)牢記的測試。測試驅(qū)動的(開發(fā))的總體原則之一就是應(yīng)測試一個類已發(fā)布的所有接口。如果客戶機能夠調(diào)用方法或訪問字段,那么就測試它。但在(Java)語言中,許多類都有一個已發(fā)布的接口容易被遺漏:通過類實例生成的串行化對象。有時這些類顯式實現(xiàn)Serializable。而有時則是直接從超類繼承這一特性。在任何一種情況下,您都應(yīng)該測試其串行化形式。本文將介紹幾種測試對象串行化的方法。

測試串行化

對串行化來說,測試極其重要,因為串行化非常非常容易出錯。在修復(fù)(bug)或優(yōu)化類時,非常容易破壞所有已有串行化對象。如果您在更改代碼時未考慮串行化,幾乎可以肯定您必將破壞原有對象。若您正在為任何形式的持久性存儲使用串行化,那么這將是一個嚴(yán)重的(bug)。即便僅為流程間的瞬時消息傳遞(如在RMI中)使用對象串行化,更改串行化格式也會使那些各類的版本不完全相同的系統(tǒng)無法順利交換數(shù)據(jù)。

告訴每一個人。將此提交到:

DiggSlashdot

幸運的是,若您謹(jǐn)慎對待串行化問題,在處理類時通??梢员苊獠患嫒莸母摹ava語言提供了多種方法,可維護一個類的不同版本之間的(兼容性),包括:

serialVersionUIDtransient修飾符readObject()和writeObject()writeReplace()和readResolve()serialPersistentFields對于這些解決方案來說,最大的問題就在于程序員未使用它們。當(dāng)您將精力集中在修復(fù)bug、添加特性或解決性能問題時,往往不會停下來思考您的更改對串行化造成的影響。然而串行化是一個涉及范圍極廣的問題跨越一個系統(tǒng)的多個不同層。幾乎所有更改都會涉及對串行化有某種影響的一個類的實例字段。這正是(單元測試)發(fā)揮作用的時機。在本文后續(xù)各節(jié)中,我將為您展示一些簡單的(單元測試),這些單元測試能確保您不會不經(jīng)意地更改可串行化類的串行格式。

回頁首

我能否將其串行化?

通常您編寫的第一個串行化測試就是用于驗證串行化是否可行的測試。即使一個類實現(xiàn)了Serializable,依然不能保證它能夠串行化。例如,如果一個可串行化的容器(如ArrayList)包含一個不可串行化的對象(如Socket),則在您嘗試串行化此容器時,將拋出NotSerializableException。

通常,對此測試,您只需在ByteArrayOutputStream上寫入數(shù)據(jù)。若未拋出任何異常,測試即通過。如果您愿意,還可測試一些已寫入的輸出。例如,清單1所示代碼片段用于測試Jaxen的BaseXPath類是否可串行化:

清單1.此類是否可串行化?

publicvoidtestIsSerializable()throwsJaxenException,IOException{BaseXPathpath=newBaseXPath(//foo,newDocumentNavigator());ByteArrayOutputStreamout=newByteArrayOutputStream();ObjectOutputStreamoos=newObjectOutputStream(out);oos.writeObject(path);oos.close();assertTrue(out.toByteArray().length0);}

回頁首

測試串行化形式

接下來,您想要編寫一個測試,不僅要驗證輸出得到了顯示,還要驗證輸出是正確的。您可通過兩種方式完成這一任務(wù):

反串行化對象,并將其與原始對象相比較。逐字節(jié)地將其與參考.ser文件相比較。我通常會從第一種選擇入手,因為它還提供了一個反串行化的簡單測試,而且編碼和實現(xiàn)相對來說比較容易。例如,清單2所示代碼片段將測試Jaxen的SimpleVariableContext類是否可寫入并在之后重新讀回:

清單2.反串行化對象,并將其與原始對象相比較

publicvoidtestRoundTripSerialization()throwsIOException,ClassNotFoundException,UnresolvableException{//constructtestobjectSimpleVariableContextoriginal=newSimpleVariableContext();original.setVariableValue(s,StringValue);original.setVariableValue(x,newDouble(3.1415292));original.setVariableValue(b,Boolean.TRUE);//serializeByteArrayOutputStreamout=newByteArrayOutputStream();ObjectOutputStreamoos=newObjectOutputStream(out);oos.writeObject(original);oos.close();//deserializebyte[]pickled=out.toByteArray();InputStreamin=newByteArrayInputStream(pickled);ObjectInputStreamois=newObjectInputStream(in);Objecto=ois.readObject();SimpleVariableContextcopy=(SimpleVariableContext)o;//testtheresultassertEquals(StringValue,copy.getVariableValue(,,s));assertEquals(Double.valueOf(3.1415292),copy.getVariableValue(,,x));assertEquals(Boolean.TRUE,copy.getVariableValue(,,b));assertEquals(,);}

讓我們再試一次

在測試代碼基礎(chǔ)中那些此前從未測試過的部分時,幾乎總是會發(fā)現(xiàn)bug,對象串行化也是這樣。在我第一次運行清單2中的測試時,測試失敗了,輸出結(jié)果如清單3所示:

清單3.不可串行化

(java).io.NotSerializableException:org.jaxen.QualifiedNameat(java).io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1075)atjava.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:291)atjava.util.HashMap.writeObject(HashMap.java:984)atsun.reflect.NativeMethodAclearcase/"target="_blank">ccessorImpl.invoke0(NativeMethod)atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)atjava.lang.reflect.Method.invoke(Method.java:585)atjava.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:890)atjava.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1333)atjava.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1284)atjava.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1073)atjava.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1369)atjava.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1341)atjava.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1284)atjava.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1073)atjava.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:291)atorg.jaxen.test.SimpleVariableContextTest.testRoundTripSerialization(SimpleVariableContextTest.java:90)

這表明,SimpleVariableContext包含一個對QualifiedName對象的引用,QualifiedName類未標(biāo)記為Serializable。我為QualifiedName的類簽名添加了implementsSerializable,這一次測試順利通過。

注意,此測試實際上并未驗證串行化格式是否正確只是驗證出對象能夠來回轉(zhuǎn)換。為測試正確性,您需要生成一些參考文件,以便與類的所有未來版本的輸出相比較。

回頁首

測試反串行化

通常,您不能依賴默認(rèn)串行化格式來保持類的不同版本間的文件格式兼容性。您必須使用serialPersistentFields、readObject()和writeObject()方法和/或transient修飾符,通過各種方式進行定制。如果您確實對類的串行化格式做出了不兼容的更改,應(yīng)相應(yīng)更改serialVersionUID字段,以指出您這樣做了。

正常情況下,您不會過分關(guān)注串行化對象的詳細結(jié)構(gòu)。而只是關(guān)注最初使用的那種格式隨著類的發(fā)展得到了維護。一旦類基本上具備了恰當(dāng)?shù)男问?,即可寫入一些類的串行化實例,并存儲在隨后可將其作為參考使用的位置處。(您很可能確實希望多多少少地考慮如何串行化才能確保足夠的靈活性,以便應(yīng)對未來的發(fā)展。)

編寫串行化實例的程序是臨時代碼,只需使用一次。實際上,您根本就不應(yīng)該多次運行這段代碼,因為您不希望獲得串行化格式中的任何意外更改。例如,清單4展示了用于串行化Jaxen的SimpleVariableContext類的程序:

清單4.寫入串行化實例的程序

importorg.jaxen.*;importjava.io.*;publicclassMakeSerFiles{publicstaticvoidmain(String[]args)throwsIOException{OutputStreamfout=newFileOutputStream(xml/simplevariablecontext.ser);ObjectOutputStreamout=newObjectOutputStream(fout);SimpleVariableContextcontext=newSimpleVariableContext();context.setVariableValue(s,StringValue);context.setVariableValue(x,newDouble(3.1415292));context.setVariableValue(b,Boolean.TRUE);out.writeObject(context);out.flush();out.close();}}

您只需將一個串行化對象寫入文件而且只需一次。這是您希望保存的文件,而不是用于寫入的代碼。清單5展示了Jaxen的SimpleVariableContext類的兼容性測試:

清單5.確保文件格式未被更改

publicvoidtestSerializationFormatHasNotChanged()throwsIOException,ClassNotFoundException,UnresolvableException{//deserializeInputStreamin=newFileInputStream(xml/simplevariablecontext.ser);ObjectInputStreamois=newObjectInputStream(in);Objecto=ois.readObject();SimpleVariableContextcontext=(SimpleVariableContext)o;//testtheresultassertEquals(StringValue,context.getVariableValue(,,s));assertEquals(Double.valueOf(3.1415292),context.getVariableValue(,,x));assertEquals(Boolean.TRUE,context.getVariableValue(,,b));assertEquals(,);}

回頁首

測試不可串行性

默認(rèn)情況下,類通常是可串行化的。例如,java.lang.Throwable或java.awt.Component的任何子類都會從其祖先繼承可串行性。在某些情況下,這也是您希望的結(jié)果,但并非總是如此。有的時候,串行化可能會成為安全漏洞,使惡意程序員能夠在不調(diào)用構(gòu)造函數(shù)或setter方法的情況下創(chuàng)建對象,從而規(guī)避了您小心翼翼地在類中構(gòu)建的所有約束性檢查。

若您希望類可串行化,就需要測試它,這與您需要測試一個直接實現(xiàn)了Serializable的類相同。如果您不希望類可串行化,則應(yīng)重寫writeObject()和readObject(),使兩者均拋出NotSerializableException,隨后您也需要對其進行測試。

此類測試的實現(xiàn)方法與其他任何JUnit異常測試相似。只需在應(yīng)拋出異常的語句兩端包圍一個try塊即可,隨后緊接欲拋出異常的語句之后添加一條fail()語句。如果愿意,您還可在catch中作出一些關(guān)于所拋出異常的斷言。例如,清單6驗證了FunctionContext是不可串行化的:

清單6.測試FunctionContext是不可串行化的

publicvoidtestSerializeFunctionContext()throwsJaxenException,IOException{DOMXPathxpath=newDOMXPath(/root/child);FunctionContextcontext=xpath.getFunctionContext();ByteArrayOutputStreamout=newByteArrayOutputStream();ObjectOutputStreamoout=newObjectOutputStream(out);try{oout.writeObject(context);fail(serializedfunctioncontext);}catch(NotSerializableExceptionex){assertNotNull(ex.getMessage());}

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論