How to test method that internally creates and uses a ServerSocket - java

My server code looks something like this:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server implements Runnable {
private ServerSocket serverSocket;
public Server(int port) throws IOException {
serverSocket = new ServerSocket(port);
}
#Override
public void run() {
try {
Socket client = serverSocket.accept();
// do stuff
} catch (IOException e) {
e.printStackTrace();
}
}
}
My plan was to write a mock client that connects to the server socket, and verifies the result, but in order to do that I need to know which port to connect to. However, this information is private.
None of the options I was thinking about are good practice I think:
If I use a predefined port number for the tests, I have no guarantee that it will be available. Even if it's available just before the test, it might be, theoretically snatched by the time I try to use it.
If I pass 0 as port number (so that ServerSocket will atomically provide a free port), I still have no access to it.
I could add a getServerPort() method to the interface or create a constructor that accepts a ServerSocket object, but changing the interface only for the sake of testing is considered bad practice.

As written, your class is not really suited for unit test.
The problem is that your direct call to new ServerSocket() basically deprives your ability to control what the socket object will be doing.
So, what you can do:
interface SocketFactory {
public ServerSocket createSocketFor(int port);
}
class SocketFactoryImpl implements SocketFactory {
...
public class Server implements Runnable {
public Server(int port) {
this(port, new SocketFactoryImpl());
}
Server(int port, SocketFactory socketFactory) {
...
In other words: you use dependency injection in order to provide a mean to your "class under test" to create those objects that it needs to do its work.
From there: you can use a mocking framework such as EasyMock in order to control what a mocked SocketFactory object will return (probably a mocked ServerSocket object). And now that you have full control over the ServerSocket used by your production code ... you can test whatever situation you want.
Long story short: don't call new; instead use dependency injection to gain full control over your class under test.
(and maybe watch these videos to really understand what writing testable code is about).

Related

java.lang.ClassCastException exception using ObjectInputStream, when sending a class as an object

https://github.com/IshayKom/RCProject
Classes As Shown in the eclipse package manager
(I don't really deal with github so I don't know how to upload classes correctly)
I got an error running my project.
I use VMWare to work on my project but I don't think that this specific error requires the use of multiple PCs or VMs.
It basically should receive ClientInformation from the InitiHandler class and start the process of matching two clients together. (Security isn't required in this project at the moment)
The steps to recreate this issue as follows: Enabling the "server" with the required information. After that go on "controlled client" mode, write the required information, and attempt to send info to the server.
I tried searching for a solution and looking at what mistake I did this time but I just can't get my mind into it. If anyone can spot my mistake it'll super helpful.
The following is the class which the error happened in:
package Server;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerInitializer extends Thread {
private int port;
private ClientInformation[] ci = null;
private ClientInformation c = null;
private boolean run = true;
ServerSocket serversocket;
ObjectInputStream ois;
Socket client;
public ServerInitializer(int port, int clientlimit) {
this.port = port;
ci = new ClientInformation[clientlimit];
start();
}
#Override
public void run() {
try
{
serversocket = new ServerSocket(port);
while(run)
{
client = serversocket.accept();
System.out.println("New Client Has Been Connected, ip:" + client.getInetAddress().getHostAddress());
ois = new ObjectInputStream(client.getInputStream());
c = (ClientInformation) ois.readObject();
new ServerThread(ci,c, client, run);
}
serversocket.close();
}
catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public void terminate()
{
this.run = false;
}
public boolean getrun()
{
return run;
}
}
The error itself:
"Exception in thread "Thread-0" java.lang.ClassCastException: class Startup.ClientInformation cannot be cast to class Server.ClientInformation (Startup.ClientInformation and Server.ClientInformation are in unnamed module of loader 'app')
at Server.ServerInitializer.run(ServerInitializer.java:35)"
If it's too much of a pain to see my mistake based on what I currently wrote let me know what to do to make it easier for you to spot it.
Another Question: How can I use the terminate function to basically disable any while loops that are happening in other classes/threads? or what I wrote is good enough? I couldn't test this because of my error. (This can apply to the server itself in my project or the client-side)
You have a class named ClientConfiguration, which has package Server; on the top. You have a completely different, totally unrelated class which by pure coincidence is also named ClientConfiguration, but has package Startup; at the top, which is why I say it is unrelated. Because that's what that means. You are then sending an instance of one of these, and upon receiving it, you assume it is the other. It isn't, hence, CCEx.
If you intended to have 2 different classes with the same name, stop confusing them; if this sounds difficult (I think it'd have some issues with this, too!), then rename one.
If you never intended to have 2 separate classes, then fix that problem. Possibly you already did and simply replaced the package statement (and moved the source file to another folder) for the only ClientConfiguration you ever had, but then one of the two (client or server) is running old code.

what is the use of ZMQueue class in JeroMQ

I checked source code of ZMQueue class from JeroMQ which implements Runnable interface looks like:
private final Socket inSocket;
private final Socket outSocket;
public ZMQQueue( Context context, Socket inSocket, Socket outSocket ){
this.inSocket = inSocket;
this.outSocket = outSocket;
}
#Override
public void run(){
zmq.ZMQ.proxy( inSocket.base(), outSocket.base(), null );
}
As you can see inside the run() only one statement is there, i.e. calling a
ZMQ.proxy() - what happens here?
And in constructor,it's taking a Context instance as a parameter and doing nothing with it.
can any one explains, for what purpose this class has implemented?
It's simple proxy that works in separate thread, it takes a msg from one socket and puts it to another, ZMQueue class is just a some kind of high-level api in jeromq/jzmq library.
Also you can use proxy without ZMQueue class (doc).
Or you can implement something more complicated by yourself with any processing you need.

CDI on Socket Wildfly or SE

I need to make a Server socket in a web application that listen for Asterisk AGI requests but i need to enable CDI injection in the socket, don't know how to do that.
Today i already have this socket working very well, the problem is i can't inject a CDI bean with the socket.
Ex:
class RequestProcessor implements Runnable
{
private Socket socket;
#Inject
private PhoneService phoneService;
#Override
public void run()
{
// Do the logic here
}
}
Method that receives the request and send to a pool.
ExecutorService pool = Executors.newCachedThreadPool();
ServerSocket server = new ServerSocket(25000);
Socket client = server.accept();
pool.execute(new RequestProcessor(client));
It's not the production code, it's just a illustrated example!
I can't make the #Inject PhoneService phoneService works.
As we've already established, newing the RequestProcessor won't populate the #Inject-annotated field since new completely cuts out the DI system. So you need a way to bring it in.
Your goal looks particularly non-trivial because RequestProcessor wants a DI-provided dependency (phoneService) and one that you provide programmatically (socket). As a general rule I would advise against mixing the two where possible – once you're using DI, it wants to spread like a virus. Let that happen. If you can design your system so that (almost) everything is injected for you, that's fanstastic!
That said, your situation is completely workable.
It looks like you have some method in some class which is a potential injection site. Assuming that this unknown class is in fact created by CDI you could #Inject the PhoneService into that class, and then pass it to the RequestProcessor constructor:
public class SomeClass {
#Inject
private PhoneService phoneService;
private void someMethod() {
ExecutorService pool = Executors.newCachedThreadPool();
ServerSocket server = new ServerSocket(25000);
Socket client = server.accept();
pool.execute(new RequestProcessor(client, phoneService));
}
}
Or you could use a factory to create RequestProcessor instances, which will basically have the same effect in the end. You can write this factory by hand, which will look pretty familiar:
public class RequestProcessorFactory {
#Inject
private PhoneService phoneService;
public RequestProcessor createNewProcessor(Socket socket) {
return new RequestProcessor(socket, phoneService);
}
}
then inject an instance of that factory into your class:
public class SomeClass {
#Inject
private RequestProcessorFactory requestProcessorFactory;
private void someMethod() {
ExecutorService pool = Executors.newCachedThreadPool();
ServerSocket server = new ServerSocket(25000);
Socket client = server.accept();
pool.execute(requestProcessorFactory.createNewProcessor(client));
}
}
There's a third way that you can do it, which is similar to Guice's assisted injection. Effectively it just generates that factory implementation for you, if you provide the interface. To my knowledge, CDI does not support this, but there is at least one CDI extension which does.
Happy DI-ing!

What is the best way to unit test a method using ServerSocket class?

I have a such method:
public boolean isFree(LdapPort port) {
boolean result = false;
try{
ServerSocket ss = new ServerSocket(port.getPortNumber());
ss.getLocalPort();
ss.close();
} catch(IOException ex){
result = true;
}
return result;
}
The problem is, that getLocalPort() operates on real system ports and during testing it passes depending on the local system.
What should be the valid way to test such method?
The ServerSocket instance should be available via factory, which (factory) is passed as a dependency to your class:
// Passing factory dependency via constructor injection
public PortChecker(IServerSocketFactory socketFactory)
{
this.socketFactory = socketFactory;
}
// ...
ServerSocket ss = this.socketFactory.GetServerSocket(port.getPortNumber());
ss.getLocalPort();
ss.close();
Then, in your unit test you can mock socketFactory to return fake server socket and as a result "disconnect" it from any real world systems.
Note that ServerSocket might also need to be abstraction (say, represented by interface/base class) so it can be mocked too.
Using PowerMock you can mock constructors, details.
So all the calls to the matching constructor of the class you want to mock can return a mock instance that you will prepare in your test.
Your test will require these annotations:
#RunWith(PowerMockRunner.class)
#PrepareForTest( ServerSocket.class )
Then inside the test method:
ServerSocket ssMock = createMock(ServerSocket.class);
expectNew(ServerSocket.class, port.getPortNumber()).andReturn(ssMock); // so constructor of the ServerSocket class taking this specific port number will return the ssMock instance
expect(ssMock.getLocalPort()).andReturn(10); // when method getLocalPort is invoked return 10
reply(ssMock, ServerSocket.class); // do not forget to specify not only the mock instance (ssMock) but the ServerSocket class as well
You need to look into mocking out the serverSocket class.
With your current code the new invocation makes testing hard.
Inject an instance of serversocket into you method/class
you can then inject a mock instance for testing
I have always found mockito a good mocking framework
You can write
public boolean isFree(LdapPort port) {
try{
new ServerSocket(port.getPortNumber()).close();
return true;
} catch(IOException ex){
return false;
}
}
And you can test it by creating a ServerSocket on the same port and isFree should be false, then close the ServerSocket and isFree should be true.

Testing Java Sockets

I'm developing a network application and I want to get unit testing right. THIS time we'll do it, you know? :)
I'm have trouble testing network connections, though.
In my application I use plain java.net.Sockets.
For example:
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Message {
byte[] payload;
public Message(byte[] payload) {
this.payload = payload;
}
public boolean sendTo(String hostname, int port) {
boolean sent = false;
try {
Socket socket = new Socket(hostname, port);
OutputStream out = socket.getOutputStream();
out.write(payload);
socket.close();
sent = true;
} catch (UnknownHostException e) {
} catch (IOException e) {
}
return sent;
}
}
I read about mocking but am not sure how to apply it.
If I was to test the code, I'd do the following.
Firstly, refactor the code so that the Socket isn't directly instantiated in the method you want to test. The example below shows the smallest change I can think of to make that happen. Future changes might factor out the Socket creation to a completely separate class, but I like small steps and I don't like making big changes on untested code.
public boolean sendTo(String hostname, int port) {
boolean sent = false;
try {
Socket socket = createSocket();
OutputStream out = socket.getOutputStream();
out.write(payload);
socket.close();
sent = true;
} catch (UnknownHostException e) {
// TODO
} catch (IOException e) {
// TODO
}
return sent;
}
protected Socket createSocket() {
return new Socket();
}
Now that the socket creation logic is outside of the method you are trying to test, you can start to mock things up and hook into the creation the socket.
public class MessageTest {
#Test
public void testSimplePayload() () {
byte[] emptyPayload = new byte[1001];
// Using Mockito
final Socket socket = mock(Socket.class);
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
when(socket.getOutputStream()).thenReturn(byteArrayOutputStream);
Message text = new Message(emptyPayload) {
#Override
protected Socket createSocket() {
return socket;
}
};
Assert.assertTrue("Message sent successfully", text.sendTo("localhost", "1234"));
Assert.assertEquals("whatever you wanted to send".getBytes(), byteArrayOutputStream.toByteArray());
}
}
Overriding individual methods on units you want to test is really useful for testing, especially in ugly code with horrible dependencies. Obviously the best solution is sorting out dependencies (in this case I would think that a Message not depend on a Socket, maybe there is a Messager interface as glowcoder suggests), but it's nice to move towards the solution in the smallest possible steps.
I'm going to answer your question as asked instead of redesigning your class (others have that covered, but the basic question on the class as written is stil valid).
Unit testing never tests anything outside the class being tested. This hurt my brain for a while--it means unit test does not in any way prove that your code works! What it does is prove that your code works the same way it did when you wrote the test.
So that said you want a unit test for this class but you also want a functional test.
For the unit test you have to be able to "Mock out" the communications. To do this instead of creating your own socket, fetch one from a "Socket factory", then make yourself a socket factory. The factory should be passed in to the constructor of this class you are testing. This is actually not a bad design strategy--you can set the hostname and port in the factory so you don't have to know about them in your communication class--more abstract.
Now in testing you just pass in a mock factory that creates mock sockets and everything is roses.
Don't forget the functional test though! Set up a "test server" that you can connect to, send some messages to the server and test the responses you get back.
For that matter, you probably want to do even deeper functional tests where you write a client that sends the REAL server some scripted commands and tests the results. You probably even want to create a "Reset state" command just for functional testing. Functional tests actually ensure that entire "Functional units" work together as you expect--something that many unit testing advocates forget.
I'm not going to say this is a bad idea.
I am going to say it can be improved upon.
If you're sending across a raw byte[] over your socket, the other side can do whatever it wants with it. Now, if you're not connecting to a Java server, then you might NEED to do that. If you're willing to say "I'm always working with a Java server" then you can use serialization to your advantage.
When you do this, you can mock it by just creating your own Sendable objects as if they came across the wire.
Create one socket, not one for every message.
interface Sendable {
void callback(Engine engine);
}
So how does this work in practice?
Messenger class:
/**
* Class is not thread-safe. Synchronization left as exercise to the reader
*/
class Messenger { // on the client side
Socket socket;
ObjectOutputStream out;
Messenger(String host, String port) {
socket = new Socket(host,port);
out = new ObjectOutputStream(socket.getOutputStream());
}
void sendMessage(Sendable message) {
out.writeObject(message);
}
}
Receiver class:
class Receiver extends Thread { // on the server side
Socket socket;
ObjectInputStream in;
Engine engine; // whatever does your logical data
Receiver(Socket socket, Engine engine) { // presumable from new Receiver(serverSocket.accept());
this.socket = socket;
this.in = new ObjectInputStream(socket.getInputStream());
}
#Override
public void run() {
while(true) {
// we know only Sendables ever come across the wire
Sendable message = in.readObject();
message.callback(engine); // message class has behavior for the engine
}
}
}
It's difficult testing connection and server interactions.
Tipically, I isolate business logic from communication logic.
I create scenarios for unit tests on business logic, these tests are automatic (use JUni,t and Maven) and i create other scenarios to test real connections, I don't use framework like JUnit for these tests.
In last year I've used Spring Mocks to test logic with HttpResponse HttpRequest, but I think this is not useful.
I follow this question.
Bye

Categories