netcoder
netcoder

Reputation: 67745

Unit testing sockets

Greetings Stackoverflowers,

I have an application in which a communication abstraction layer exists. Each implementation in this layer, called a connector, provides my application with a way of exchanging data with a connected peer (e.g.: through HTTP, TCP sockets, UDP sockets, etc.).

Per example, I have a Connector_Tcp class that implements methods such as read, write, open and close.

I need to write a unit test for that class. I know that unit tests should have as less dependencies as possible. Unfortunately, in that case, the dependency is a system resource: a socket; and I cannot bypass it.

I need some advice on how to go about unit testing this class.

In my opinion, even though this class is using a system resource, it should be tested as all the other connectors to make sure that it respects the standard established by my application.

I am concerned about such things as binding collisions (Address already in use errors) and blocking. I don't want the unit test to fail because the port is already in use by a system service that has nothing to do with my application.

I have done a lot of unit tests in my days, but none of which relies on such a low-level resource that are sockets.

How would you go about unit testing a socket-dependent class? Open a socket for every unit? Use a single server class, then a manually-defined socket resource to connect to it and test it...?

I guess my problem really is the following:

If the unit test fails... how do I know if:

I need the unit test to test only if the method has been behaving properly or not...

Upvotes: 10

Views: 5669

Answers (2)

axw
axw

Reputation: 7083

I've written a similar abstraction layer, albeit in C/C++, and I have had occasion to unit-test the socket based code. I don't know if there's anything inherently specific to PHP here, so I'll just offer what generic advice I can.

  • Create a server socket in your setup, close it in the tear down. Depending on whether you support many clients connecting to the server socket, you may want to do that part in the test method.
  • Assuming you can specify the port to connect to in your client code, have the server socket bind to port 0 (ephemeral port), and then use this in the client code. This will eliminate the problem of binding to a port already in use.
  • Set timeouts on your sockets. If your test fails for some unexpected reason, you don't want it hanging waiting for a connection forever.
  • You need to be able to interleave the client/server behaviour. For example, you'll want to test what happens if the server shuts down its side of the connection half way through a client read/write. Either asynchronous I/O or multi-threading will do the job. I'm not sure what you have at your disposal in PHP.

Upvotes: 5

Charlie Flowers
Charlie Flowers

Reputation: 17457

I hope I'm understanding your question properly ... if not, please let me know. But what I would do is mock the socket. That would let you write a series of unit tests that ensure that your method does all the right things in various cases.

For example, you could write one unit test that tells the socket mock instance to throw a "port not available" exception. In that case, you could assert that your method caught the exception and logged it with the same text that was in the exception.

And even more central to the issue, you could write a unit test that tells the socket mock instance to return a valid stream of bytes from read(), and then you could assert that your method does the right thing(s) with those bytes.

So you're not actually testing the socket. You're setting up the socket to simulate certain occurrences, and you're testing to see if your code that works with the socket is doing the right things.

(I've used mocking frameworks in Java, C#, Ruby and JavaScript. I've never worked with PHP, but I bet there are some good mocking frameworks out there for it).

EDIT: Yes, there are some mocking frameworks for PHP out there. I can't recommend one, but here are a couple I was able to find: PHPUnit and LastCraft

Upvotes: 2

Related Questions