3
votes

I'm new to unit testing. I understood the principles of it, but I still can't figure out how to test my current project. I need to test void methods, operating with java.nio.SocketChannel. These methods are:
- initSelector, where I open selector, bind new ServerSocketChannel and register it
- read, which reads data and puts it to a queue (should i write extra method for verifying, if that data actually exists in queue? and in that case, should i write tests for that methods?)
- write method, which takes data from a queue and writes it to a SocketChannel

I can test this methods for not throwing IOException, but what else?
And how should I test run() method of a Thread? Or is it not unit testing, but system or other?

3

3 Answers

2
votes

Basically, you have two possibilities:

  • if you want to thoroughly unit test these methods, you should hide the concrete (hardware dependent components like sockets etc. behind mockable interfaces, and use mocks in the unit tests to verify that the expected calls with the expected parameters are made to these objects
  • or you can write integration / system tests using the real sockets within the whole component / app, to verify that the correct sockets are opened, data is transferred properly etc.

Ideally, you should do both, but in the real world, unit testing may not always be feasible. Especially for such low-level methods, which depend on some external software/hardware component like sockets, DBs, file system etc. Then the best approach is to leave as little logic (thus as little possibilities for failure) in these methods / layers as possible, and abstract out the logic into a higher layer, designed to be unit testable (using mockable interfaces as mentioned above).

To test threads, you can just run() them from your unit test as usual. Then most likely you need to wait for some time before trying to get and verify the results produced by the thread.

Again, if you abstract away the actual logic of the task into e.g. a Callable or Runnable, you can unit test it in isolation much easier. And this also enables you to use the Executor framework (now or later), which makes dealing with concurrency much easier and safer.

2
votes

So first, if you are using a real SocketChannel in your unit test, it is not a unit test. You should use a mock (consider Mockito) for the SocketChannel. Doing so will allow you to provide a controlled stream of bytes to the method under test and verify what bytes are passed to the channel.

If your class is creating the instance of the SocketChannel, consider changing the class to accept a SocketChannelFactory. Then you can inject a SocketChannelFactory mock which returns a SocketChannel mock.

You can just call run() directly in your unit test.

Mockito link

0
votes

run() is a method like any other, so you should just be able to call it from a unit test (depending on if it's running in an endless loop of course - then you might want to test the methods that run() is calling).
For the SocketChannel I'd say you don't want to test the SocketChannel itself; you want to test how your code interacts with the SocketChannel given a certain set of start conditions.
So you could look into creating a mock for it, and having your code talk to the mock. That way you can verify if your code is interacting with the channel in the way you expect (read(), write() and so on).
Check out http://code.google.com/p/powermock/ for example.