为了账号安全,请及时绑定邮箱和手机立即绑定

如何模拟 objectOutputStream.writeObject()?

如何模拟 objectOutputStream.writeObject()?

UYOU 2022-09-01 16:24:29
我想做什么我有一个服务器类,它故意没有传递给它的参数,并希望使用Mockito对其进行测试。如果你想在Github上查看完整的源代码:服务器服务器测试服务器.classpublic 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 的典型情况,当遇到最终方法时。服务器测试.class我尝试了什么在其他文章中有人建议,可以通过实现接口来更改所测试类的签名来规避最终问题,因此无论如何都会模拟它。ObjectInput然而,在所提出的方法中,当不作为参数传递给被测类时,不清楚如何操作。ObjectOutputStream另外,当您直接控制一个 的响应时,如何操作,如我的结构所示,这对于 TCP 客户端/服务器应用程序来说并不罕见。ObjectInputStreamObjectOutputStreamcase到目前为止,我的印象是我的测试可以工作,如果不是签名中的最终关键字。如果我错了,请在这里纠正我。ObjectOutputStream问:“为什么我不将流传递到服务器?答:因为我在其他任何地方都不需要它们。这真的是最后的努力,如果有必要,我会的,但我宁愿不这样做。
查看完整描述

2 回答

?
慕码人2483693

TA贡献1860条经验 获得超9个赞

您可以在类中提供一个函数,该函数读取输入流并模拟它而不是方法:ServerfromClientObjectInputStream.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


查看完整回答
反对 回复 2022-09-01
?
牧羊人nacy

TA贡献1862条经验 获得超7个赞

问题中的误解

我知道Mockito不能模拟最终类,例如ObjectOutputStream和ObjectInputStream。> 这正是我遇到问题的地方。

到目前为止,我的测试在线NullPointerException失败

when(server.fromClient.readObject()).thenReturn(0x2);.

这是 Mockito 的典型情况,当遇到最终方法时。

您的 NPE 不是由于 Mockitos 无法模拟方法引起的。NPE 的原因是您的成员变量,并且在测试代码尝试访问它们时未初始化。finalfromClienttoClient

但即使如此,它们也会使用真实依赖项的实例进行初始化,而不是使用模拟,因此Mockito无论如何都无法配置它们。

您从根本上误解了 .你永远不会嘲笑你的班级被测试。您始终模拟受测类的依赖项,并将受测代码的实际依赖项替换为此模拟。mocks

在其他文章中有人建议,可以通过实现接口来更改所测试类的签名来规避 -问题,因此无论如何都会模拟它。finalObjectInput

不。

您建议针对接口进行编程,而不是针对具体类进行编程,并使用依赖注入/控制反转

没有人建议你测试的类(这是你的类)应该实现任何接口。Server

违反 OOP 最佳实践

问:“为什么我不将流传递到服务器?
答:因为我在其他任何地方都不需要它们。

这真的是最后的努力,如果有必要,我会的,但我宁愿不这样做。

我们做OOP的主要原因之一是我们代码的可重用性

单元测试是代码最明显的首次重用。在测试代码时遇到困难会发现缺乏可重用性。在这一点上,你的类根本不应该被“重用”并不重要。这是您的通用编码方法,它将使您将来遇到麻烦。Server

您的类存在一些违反 OOP 最佳实践的行为:Server

  • 封装/信息隐藏。

    您最有可能将成员变量和包声明为私有,以便能够从我们的测试中访问它们。这在两个方面存在问题:fromClienttoClient

    1. 您的代码永远不应该公开成员变量等实现细节(除了它是DTO/ValueObject)。

    2. 切勿为启用测试而显式修改生产代码。

  • 关注点分离

    任何类(提供业务逻辑)都应该有一个单一的责任。依赖项的实例化是一个完全不同的责任,这与您的业务逻辑不同。因此,您的类不应负责执行此实例化。Server

    我知道这有点教条,但它会带来更好的可测试性,因此更好的可重用代码。再说一遍:如果你的代码目前根本不打算重用,这并不重要。

结论

恕我直言,您真正的问题是:如何在不适应OOP最佳实践的情况下测试我的代码?

在这种情况下,您应该通过使用PowerMock明确地放弃糟糕的设计。


查看完整回答
反对 回复 2022-09-01
  • 2 回答
  • 0 关注
  • 93 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号