简体   繁体   English

如何模拟objectOutputStream.writeObject()?

[英]How to mock objectOutputStream.writeObject()?

What I'm trying to do 我想做什么

I have a server class that has intentionally no arguments passed to it and want to test it with Mockito. 我有一个服务器类,故意没有将任何参数传递给它,并且想用Mockito测试它。

If you want to check out the full source code on Github : 如果您想在Github上查看完整的源代码:

Server.class 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();
    }
}

The Problem 问题

I understand that Mockito can't mock final classes, such as ObjectOutputStream and ObjectInputStream. 我知道Mockito无法模拟最终类,例如ObjectOutputStream和ObjectInputStream。

This is exactly where I run into Problems. 这正是我遇到问题的地方。

So far, my test is failing with NullPointerException on line 到目前为止,我的测试失败,并在网上显示NullPointerException

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

This is typical for Mockito, when running into final methods. 当运行最终方法时,这对于Mockito是典型的。

ServerTest.class 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());

    }

What I tried 我尝试了什么

It was suggested in other posts that it's possible to circumvent the final -problem, by changing the signature of the class under test by implementing the interface ObjectInput and therefore mock it anyway. 其他文章中 ,建议可以通过实现接口ObjectInput更改被测试类的签名来规避最终的问题,因此无论如何都要对其进行模拟。

However in the proposed approach it's unclear how to operate when not passing ObjectOutputStream as an argument to the class under test. 但是,在提出的方法中,当不将ObjectOutputStream作为参数传递给被测类时,尚不清楚如何操作。

Also, how to operate when you have the ObjectInputStream directly controlling a response of an ObjectOutputStream , as seen with my case structure, which is not untypical for TCP client/server applications. 此外,如我的case结构所示,当让ObjectInputStream直接控制ObjectOutputStream的响应时如何操作,这对于TCP客户端/服务器应用程序来说并非不常见。

So far I'm under the impression that my test would work, would it not be for the final keyword in the signature of ObjectOutputStream . 到目前为止,我仍然认为我的测试可以工作,而不是ObjectOutputStream签名中的final关键字。 Correct me here if I'm wrong. 如果我错了,请在这里纠正我。

Q: "Why am I not passing the streams to the server?" 问: “为什么不将流传递到服务器?” A: Because I don't need them anywhere else. 答:因为我在其他任何地方都不需要它们。

It's really a last ditch effort to do so and I will if I have to, but I would rather not. 这样做实际上是最后的努力,如果需要,我会这样做,但我宁愿不这样做。

You can provide a function in your Server class that reads fromClient input stream and mock it instead of ObjectInputStream.readObject() method: 您可以在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();
     }

     //...

So your test would look like this: 因此您的测试将如下所示:

    @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());
    }

The same thing can be applied to toClient stream as well. 同样的事情也可以应用于toClient流。

Misunderstanding in your question 您的问题中的误解

I understand that Mockito can't mock final classes, such as ObjectOutputStream and ObjectInputStream. 我知道Mockito无法模拟最终类,例如ObjectOutputStream和ObjectInputStream。 > This is exactly where I run into Problems. >这正是我遇到问题的地方。

So far, my test is failing with NullPointerException on line 到目前为止,我的测试失败,并在网上显示NullPointerException

when(server.fromClient.readObject()).thenReturn(0x2);. 当(server.fromClient.readObject())。thenReturn(0X2);.

This is typical for Mockito, when running into final methods. 当运行最终方法时,这对于Mockito是典型的。

Your NPE is not caused from Mockitos inability to mock final methods. 您的NPE 并非由Mockitos无法模拟final方法引起。 The reason for the NPE is that your member variables fromClient and toClient are not initialized when your test code tries to access them. 使用NPE的原因是,当测试代码尝试访问成员变量fromClienttoClient它们不会被初始化。

But even if, they would be initialized with instances of the real dependencies and not with mocks so that Mockito wouldn't be able to configure them anyway. 但即使,他们将与实际依赖性的实例初始化,而不是与嘲笑 ,这样会的Mockito无法反正配置它们。

You fundamentally misunderstand the purpose and the technical implications of mocks . 你从根本上误解的目的和技术含义mocks You never mock your class under test. 永远不会嘲笑要测试的课程。 You always mock the dependencies of your class under test and replace the real dependencies of your Code Under Test with this mocks. 您总是模拟被测类的依赖关系 ,并用此模拟物替换被测代码的实际依赖关系。

It was suggested in other posts that it's possible to circumvent the final -problem, by changing the signature of the class under test by implementing the interface ObjectInput and therefore mock it anyway. 在其他文章中,建议可以通过实现接口ObjectInput更改被测试类的签名来规避final问题,因此无论如何都要对其进行模拟。

No. 没有。

You where suggested to to program against interfaces instead of programming against concrete classes and to use Dependency Injection / Inversion of control . 建议您针对接口进行编程,而不是针对具体类进行编程,并建议使用依赖注入/控制反转

No one suggested tat you class under test (which is your Server class) should implement any interface. 没有人建议您在测试中的类(您的Server类)实现任何接口。

Violating OOP best practices 违反OOP最佳做法

Q: "Why am I not passing the streams to the server?" 问:“为什么不将流传递到服务器?”
A: Because I don't need them anywhere else. 答:因为我在其他任何地方都不需要它们。

It's really a last ditch effort to do so and I will if I have to, but I would rather not. 这样做实际上是最后的努力,如果需要,我会这样做,但我宁愿不这样做。

One of the main reasons why we do OOP is re-usability of our code. 我们进行OOP的主要原因之一是代码的可重用性

A unit test is the most obvious first re-usage of your code. 单元测试是最明显的代码重用。 Having trouble testing your code reveals the lack of re-usability. 测试您的代码有困难,这表明缺乏可重用性。 At this point it does not matter that your Server class is not meant to be "re-used" at all. 在这一点上,您的Server类根本不打算“重用”并不重要。 It is your general coding approach that will let you run into trouble in future. 这是您的通用编码方法,将来会让您遇到麻烦。

Your Server class has some violations of OOP best practices: 您的Server类违反了OOP最佳做法:

  • encapsulation/information hidig. 封装/信息隐藏。

    You declared the member variables fromClient and toClient package private most likely in order to be able to access them from our test. 您最有可能将成员变量fromClienttoClient 声明为私有 ,以便能够从我们的测试中访问它们。 This is problematic in two ways: 这有两个方面的问题:

    1. Your code should never expose implementation details like member variables (except it is a DTO/ValueObject). 您的代码不应公开成员变量之类的实现细节 (除非它是DTO / ValueObject)。
    2. You should never modify your production code explicitly for enabling testing. 您绝对不应显式修改生产代码以启用测试。
  • separation of concerns 关注点分离

    Any class (providing business logic) should have a single responsibility . 任何类(提供业务逻辑)都应承担单个责任 Instantiation of dependencies is a completely different responsibility apart from what ever your business logic is. 除了业务逻辑之外,实例化依赖项是完全不同的责任。 So your Server class should not be responsible for doing this instantiation. 因此,您的Server类不应负责执行此实例化。

    I know that this is a bit dogmatic, but it leads to better testable and hence better re-usable code. 我知道这有点教条,但是它会导致更好的可测试性和可重用性的代码。 And again: it does not matter if your code is currently not meant to be re-used at all. 再说一遍: 当前是否不打算重用您的代码并不重要。

Conclusion 结论

IMHO your real question is: How can I test my code without adapting best practices of OOP? 恕我直言,您真正的问题是: 如何在不采用OOP最佳实践的情况下测试我的代码?

In that case you should explicitly commit your surrender to bad design by using PowerMock . 在这种情况下,您应该使用 PowerMock 明确将您的投降提交至不良设计。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么ObjectOutputStream.writeObject不采用Serializable? - Why does ObjectOutputStream.writeObject not take a Serializable? ObjectOutputStream.writeObject 对文件线程安全吗? - Is ObjectOutputStream.writeObject to a file thread safe? NockPointerException当Mockito嘲笑ObjectOutputStream.writeObject吗? - NullPointerException when Mockito mocking ObjectOutputStream.writeObject? 使用ObjectOutputStream.writeObject()无法进行数据传输 - data transfer not working using ObjectOutputStream.writeObject() 我应该同步 ObjectOutputStream.writeObject(Object) 吗? - Should I synchronize ObjectOutputStream.writeObject(Object)? 如何使用ObjectOutputStream.writeObject()+ Base64(Java)对对象进行深度序列化? - How to deep serialize object using ObjectOutputStream.writeObject()+Base64 (Java)? Java,ObjectOutputStream.writeObject将随机符号打印到文件 - Java, ObjectOutputStream.writeObject prints random symbols to file 尝试在类之间写入 object 时 ObjectOutputStream.writeObject() 冻结 - ObjectOutputStream.writeObject() freezing when trying to write object between classes 为什么在写字节数组时ObjectOutputStream.writeObject比写字节快? - Why is ObjectOutputStream.writeObject faster than write bytes when writing a byte array? 编写可序列化的对象时,ObjectOutputStream.writeObject()(在socket.getOutputStream()顶部)抛出断线(IO异常) - ObjectOutputStream.writeObject() (on top of socket.getOutputStream()) throws broken pipe (IO Exception) when writing a serializable object
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM