![](/img/trans.png)
[英]Why does ObjectOutputStream.writeObject not take a Serializable?
[英]How to mock objectOutputStream.writeObject()?
我有一個服務器類,故意沒有將任何參數傳遞給它,並且想用Mockito測試它。
如果您想在Github上查看完整的源代碼:
Server.class
public class Server extends Thread {
private Other other;
ObjectInputStream fromClient;
ObjectOutputStream toClient;
public Server(){
this.other = new Other(foo, bar);
}
@Override
public void run(){
try{
ServerSocket serverSocket = new ServerSocket(1337);
Socket socket = serverSocket.accept();
fromClient = new ObjectInputStream(socket.getInputStream());
toClient = new ObjectOutputStream(socket.getOutputStream());
while(true) {
int command = (Integer) fromClient.readObject();
switch (command) {
case 0x1:
//add
//...
break;
case 0x2:
//get server data
toClient.writeObject(other.getSomething());
break;
case 0x3:
//delete
//...
break;
default:
break;
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread t = new Server();
t.start();
}
}
問題
我知道Mockito無法模擬最終類,例如ObjectOutputStream和ObjectInputStream。
這正是我遇到問題的地方。
到目前為止,我的測試失敗,並在網上顯示NullPointerException
when(server.fromClient.readObject()).thenReturn(0x2);
。
當運行最終方法時,這對於Mockito是典型的。
ServerTest.class
@Test
void run() throws IOException, ClassNotFoundException {
//given
Other other = new Other(foo, bar);
Server server = mock(Server.class);
//when
when(server.fromClient.readObject()).thenReturn(0x2);
server.start();
//then
verify(server).toClient.writeObject(other.getSomething());
}
在其他文章中 ,建議可以通過實現接口ObjectInput
更改被測試類的簽名來規避最終的問題,因此無論如何都要對其進行模擬。
但是,在提出的方法中,當不將ObjectOutputStream
作為參數傳遞給被測類時,尚不清楚如何操作。
此外,如我的case
結構所示,當讓ObjectInputStream
直接控制ObjectOutputStream
的響應時如何操作,這對於TCP客戶端/服務器應用程序來說並非不常見。
到目前為止,我仍然認為我的測試可以工作,而不是ObjectOutputStream
簽名中的final關鍵字。 如果我錯了,請在這里糾正我。
問: “為什么不將流傳遞到服務器?” 答:因為我在其他任何地方都不需要它們。
這樣做實際上是最后的努力,如果需要,我會這樣做,但我寧願不這樣做。
您可以在Server
類中提供一個從fromClient
輸入流讀取並模擬它的函數,而不是ObjectInputStream.readObject()
方法:
public class Server extends Thread {
private Other other;
ObjectInputStream fromClient;
ObjectOutputStream toClient;
public Server(){
this.other = new Other(foo, bar);
}
Object readObject() throws ClassNotFoundException, IOException {
return fromClient.readObject();
}
//...
因此您的測試將如下所示:
@Test
void run() throws IOException, ClassNotFoundException {
//given
Other other = new Other(foo, bar);
Server server = mock(Server.class);
//when
when(server.readObject()).thenReturn(0x2);
server.start();
//then
verify(server).toClient.writeObject(other.getSomething());
}
同樣的事情也可以應用於toClient
流。
我知道Mockito無法模擬最終類,例如ObjectOutputStream和ObjectInputStream。 >這正是我遇到問題的地方。
到目前為止,我的測試失敗,並在網上顯示NullPointerException
當(server.fromClient.readObject())。thenReturn(0X2);.
當運行最終方法時,這對於Mockito是典型的。
您的NPE 並非由Mockitos無法模擬final
方法引起。 使用NPE的原因是,當測試代碼嘗試訪問成員變量fromClient
和toClient
它們不會被初始化。
但即使,他們將與實際依賴性的實例初始化,而不是與嘲笑 ,這樣會的Mockito無法反正配置它們。
你從根本上誤解的目的和技術含義mocks
。 您永遠不會嘲笑要測試的課程。 您總是模擬被測類的依賴關系 ,並用此模擬物替換被測代碼的實際依賴關系。
在其他文章中,建議可以通過實現接口
ObjectInput
更改被測試類的簽名來規避final
問題,因此無論如何都要對其進行模擬。
沒有。
建議您針對接口進行編程,而不是針對具體類進行編程,並建議使用依賴注入/控制反轉 。
沒有人建議您在測試中的類(您的Server
類)實現任何接口。
問:“為什么不將流傳遞到服務器?”
答:因為我在其他任何地方都不需要它們。這樣做實際上是最后的努力,如果需要,我會這樣做,但我寧願不這樣做。
我們進行OOP的主要原因之一是代碼的可重用性 。
單元測試是最明顯的代碼重用。 測試您的代碼有困難,這表明缺乏可重用性。 在這一點上,您的Server
類根本不打算“重用”並不重要。 這是您的通用編碼方法,將來會讓您遇到麻煩。
您的Server
類違反了OOP最佳做法:
封裝/信息隱藏。
您最有可能將成員變量fromClient
和toClient
包聲明為私有 ,以便能夠從我們的測試中訪問它們。 這有兩個方面的問題:
關注點分離
任何類(提供業務邏輯)都應承擔單個責任 。 除了業務邏輯之外,實例化依賴項是完全不同的責任。 因此,您的Server
類不應負責執行此實例化。
我知道這有點教條,但是它會導致更好的可測試性和可重用性的代碼。 再說一遍: 當前是否不打算重用您的代碼並不重要。
恕我直言,您真正的問題是: 如何在不采用OOP最佳實踐的情況下測試我的代碼?
在這種情況下,您應該使用
PowerMock
明確將您的投降提交至不良設計。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.