Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I unit test socket code with PHPUnit?

I currently have a Socket class, which is basically just an OO wrapper class for PHP's socket_* functions:

class Socket {
    public function __construct(...) {
        $this->_resource = socket_create(...);
    }

    public function send($data) {
        socket_send($this->_resource, $data, ...);
    }

    ...
}

I don't think I can mock the socket resource since I'm using PHP's socket functions, so right now I'm stuck as to how to reliably unit test this class.

like image 902
FtDRbwLXw6 Avatar asked Feb 03 '12 22:02

FtDRbwLXw6


People also ask

Where do I put PHPUnit test?

You can run all the tests in a directory using the PHPUnit binary installed in your vendor folder. You can also run a single test by providing the path to the test file.

What is PHPUnit testing?

PHPUnit is a unit testing framework for the PHP programming language. It is an instance of the xUnit design for unit testing systems that began with SUnit and became popular with JUnit. Even a small software development project usually takes hours of hard work.

What is PHPUnit used for?

PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks. PHPUnit 9 is the current stable version. PHPUnit 10 is currently in development.


1 Answers

You appear to be missing a small piece to the unit test mindset.

Your problem is easily solvable by creating a Stub object. Strangely, I give this answer time and time again, so it must be largely missed by a lot of people.

Because I see so much confusion as to the differences between stubs and mocks, let me lay it out here, as well...

  • A mock is a class that extends another class that the test is directly dependent on, in order to change behaviors of that class to make testing easier.
  • A stub is a class that *implements an API or interface** that a test cannot test easily directly on its own, in order to make testing possible.

^-- That is the clearest description of the two I've ever read; I should put it on my site.

Sockets have this nice feature where you can bind to port 0 for testing purposes (seriously, it's called the "ephemeral port").

So try this:

class ListeningServerStub
{
    protected $client;

    public function listen()
    {
        $sock = socket_create(AF_INET, SOCK_STREAM, 0);

        // Bind the socket to an address/port
        socket_bind($sock, 'localhost', 0) or throw new RuntimeException('Could not bind to address');

        // Start listening for connections
        socket_listen($sock);

        // Accept incoming requests and handle them as child processes.
        $this->client = socket_accept($sock);
    }

    public function read()
    {
        // Read the input from the client – 1024 bytes
        $input = socket_read($this->client, 1024);
        return $input;
    }
}

Create this object and set it to listen in your test's setUp() and stop listening and destroy it in the tearDown(). Then, in your test, connect to your fake server, get the data back via the read() function, and test that.

If this helps you out a lot, consider giving me a bounty for thinking outside the traditional box ;-)

like image 178
Theodore R. Smith Avatar answered Sep 20 '22 06:09

Theodore R. Smith