简体   繁体   中英

AKKA - How can I unit test my actor that handle a TCP connection?

I have an actor that binds a port a the preStart and then expect the Tcp.Bound message. Then, it will just wait for a Tcp.Connected to happen. This actor does not provides anything to its creator so I would like to receive the Tcp Message and/or mock the Tcp Manager

So far I tried to subscribe my TestKit Probe to the tcp messages. Other than that I am looking to create a class that would override the manager, but still don't know how to do it. I am using Java 8 and JUnit 5.

@Override
    public void preStart() {
         this.connection = Tcp.get(getContext().getSystem()).manager();
         this.connection.tell(TcpMessage.bind(getSelf(), remoteAddress, 100), getSelf());
    }

 @Override
    public AbstractActor.Receive createReceive() {
        return receiveBuilder()
                .match(Tcp.Bound.class, msg -> {
                    log.debug("Port Bound : [{}]", msg.localAddress());
                    this.sessionHandler = getContext().actorOf(RmiSessionHandler.props(getSelf(), settings));
                    this.buffer = getContext().actorOf(RmiBuffer.props(this.sessionHandler, settings));
                    this.connection = getSender();

                }).match(Tcp.Connected.class, msg -> {
                    log.debug("Port Connected to : [{}])", msg.remoteAddress());
                    this.sessionHandler.tell(msg, getSelf());
                    sender().tell(TcpMessage.register(getSelf()), getSelf()); // Register ourselves
                    this.session = getSender();
                    this.isConnectedToClient = true;

You can see that my actor just creates other actors, but I don't want to go through them to test that he established the connection.

Would really like to know when my actor is sending Tcp.Bind or when a port is bound and on which port.

Here is what I've tried :

system = ActorSystem.create("sessionHandlerTest");
testProbe = new TestKit(system);
system.eventStream().subscribe(testProbe.getRef(), Tcp.Bound.class);
rmiSocket = system.actorOf(RmiSocket.props(testProbe.getRef(), settings));
Tcp.Bound bindingMessage = testProbe.expectMsgClass(Tcp.Bound.class);

Also I tried to register my probe to the tcp manager :

ActorRef tcpManager = Tcp.get(system).manager();
tcpManager.tell(TcpMessage.register(testProbe.getRef()), testProbe.getRef());

So, in short let's assume you have a class A that needs to connect to a database. Instead of letting A actually connect, you provide A with an interface that A may use to connect. For testing you implement this interface with some stuff - without connecting of course. If class B instantiates A it has to pass a "real" database connection to A. But that means B opens a database connection. That means to test B you inject the connection into B. But B is instantiated in class C and so forth.

So at which point do I have to say "here I fetch data from a database and I will not write a unit test for this piece of code"?

In other words: Somewhere in the code in some class I must call sqlDB.connect() or something similar. How do I test this class?

And is it the same with code that has to deal with a GUI or a file system?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM