You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Second, I was trying to setup a basic and global integration test directly as a PHPUnit test which tests the following:
Client can connect as expected with a specific websocket server
Client can communicate as expected with the connected websocket server
Client receives responses (if any response is delivered immediately) as expected from a message sent to the websocket server
So I initially tried something like this:
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use WebSocket\Client;
use WebSocket\Connection;
use WebSocket\Middleware\CloseHandler;
use WebSocket\Middleware\PingResponder;
final class WebsocketsIntegrationTest extends TestCase
{
public function test_websocket_connection()
{
$client = new Client('wss://echo.websocket.org/?auth=123xyz');
$client
// Add standard middlewares
->addMiddleware(new CloseHandler())
->addMiddleware(new PingResponder())
// Listen to incoming Text messages
->onText(
function (
Client $client,
Connection $connection,
$message
) {
// Assert incoming message
$this->assertSame(
expected: 'Hello, world!',
actual : $message->getContent()
);
$client->close();
}
)
->start();
}
}
But, as the start method never returns, this will cause a never concluding test execution. So I have been digging for a lot of time for a suitable solution for an integration test that is ideally executable using PHP, and ideally within PHPUnit. So the only feasible and easy solution I could find is using wscat but integrating its execution and test assertions within PHP,as follows. On my mac, it perfectly works:
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class WebsocketsIntegrationTest extends TestCase
{
public function test_websocket_connection()
{
$descriptorspec = [
// stdin
0 => [
"pipe",
"r"
],
// stdout
1 => [
"pipe",
"w"
],
// stderr
2 => [
"pipe",
"w"
]
];
$process = proc_open(
"wscat -c wss://echo.websocket.org/?auth=123xyz",
$descriptorspec,
$pipes
);
if (is_resource($process)) {
// Allow some time for the connection to be established (max timeout of 3 seconds)
sleep(3);
/**
* Next, to test that your websocket integration works as expected, send the messages you want to, and also
* provide the response you expected to be delivered in response to it, to verify that the websockets
* server responds as expected.
*/
$messages = [
/**
* Send an empty message, to verify that the websocket service responds as intended to it.
*/
[
'request_body' => '',
'expected_response_body' => "> {\"status\" : \"connected\"}",
]
];
foreach ($messages as $message) {
fwrite(
$pipes[0],
/**
* The newline character is crucial as it corresponds to hitting enter in the CLI
* (submit the message)
*/
"{$message['request_body']}\n"
);
/**
* The websocket server is expected to respond immediately, hence waiting one second should be enough
*/
sleep(1);
}
// Close the stdin pipe, as no more input will be provided
fclose($pipes[0]);
/**
* Terminate the process to simulate CTRL + C.
* Note that this command is immediately executed, which is why the sleep calls above are needed.
*/
proc_terminate($process);
// Get the output of the stdout and stderr pipes
$output = stream_get_contents($pipes[1]);
$errors = stream_get_contents($pipes[2]);
// Close the stdout and stderr pipes
fclose($pipes[1]);
fclose($pipes[2]);
// Close the process and get the termination status
$return_value = proc_close($process);
/**
* Order will be conserved with explode, so assert the message responses in the order of their request, as
* any pipe is a FIFO structure (https://www.sitepoint.com/proc-open-communicate-with-the-outside-world/).
*
* Every response delivered by the websocket server that was currently setup responds with an ending newline
* character in the CLI. To thus get all responses, explode the obtained stdout string via the newline
* characters as the separator, and then kick off the last element to disregard the trailing newline
* characters (which would otherwise lead to an additional empty string as expected response at index n + 1)
* You may have to adapt this according to your response logic of your websockets server
*/
$responses = explode(
separator: "\n",
string : $output
);
array_pop($responses);
foreach ($responses as $index => $response) {
/**
* Assert that the websocket server responded as expected for every submitted message
*/
$this->assertSame(
$messages[$index]['expected_response_body'],
$response,
"An unexpected response body was received from the websocket server; $response instead of the expected {$messages[$index]['expected_response_body']}."
);
}
/**
* No errors should have been encountered
*/
$this->assertEmpty(
$errors,
"Errors encountered: $errors"
);
/**
* proc_terminate() by defaults sends 15 as the signal to the running process; so that's the expected
* integer output here
*/
$this->assertEquals(
15,
$return_value,
"Process exited with code $return_value"
);
} else {
$this->fail("The command used to start the websocket server failed to execute");
}
}
}
Of course, for this solution, you need wscat, but for me it's totally worth it for the testing.
So I just wanted to share it here to provide a concrete real-life integration test solution in PHP with websocket servers, as your testing relies on mocking only. Just in case anyone using your library as me is looking for the same thing, thanks again for the package!
This discussion was converted from issue #80 on January 02, 2025 09:29.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
First of all, thanks for this package!
Second, I was trying to setup a basic and global integration test directly as a PHPUnit test which tests the following:
So I initially tried something like this:
But, as the
start
method never returns, this will cause a never concluding test execution. So I have been digging for a lot of time for a suitable solution for an integration test that is ideally executable using PHP, and ideally within PHPUnit. So the only feasible and easy solution I could find is usingwscat
but integrating its execution and test assertions within PHP,as follows. On my mac, it perfectly works:Of course, for this solution, you need wscat, but for me it's totally worth it for the testing.
So I just wanted to share it here to provide a concrete real-life integration test solution in PHP with websocket servers, as your testing relies on mocking only. Just in case anyone using your library as me is looking for the same thing, thanks again for the package!
Beta Was this translation helpful? Give feedback.
All reactions