swoole / swoole-src

🚀 Coroutine-based concurrency library for PHP
https://www.swoole.com
Apache License 2.0
18.44k stars 3.16k forks source link

Coroutine and Phpunit #3844

Closed matiux closed 3 years ago

matiux commented 3 years ago

I have a service that loop over some http calls

use Co\Http\Client;

class CsvRowProcessor
{
    private array $responses = [];

    public function execute(array $row): array
    {
        $descriptions = explode(';', trim($row['descriptions']));
        $url = (string) $row['url'];

        foreach ($descriptions => $description) {
            go(function () use ($url, $description) {
                $this->callUrl($url, $description);
            });
        }

        return $this->responses;
    }

    private function callUrl(string $url, string $description): void
    {
        $host = parse_url($url)['host'];
        $client = new Client($host, 9501);
        $url = sprintf('%s=%s', $url, $description);
        $client->get($url);

        $client->close();

        $this->responses[] = $this->buildResponse($url, $client);
    }
}

Than I'd like to have a test on this service

class CsvRowProcessorTest extends TestCase
{
    /**
     * @test
     */
    public function should_process_csv_row(): void
    {
        $row = [
            'url' => 'http://localhost:9501/entries?description',
            'descriptions' => 'time;ate;red;dog',
        ];

        $csvRowProcessor = new CsvRowProcessor();

        $resp = $csvRowProcessor->execute($row);

        self::assertCount(4, $resp);
    }
}

Obviously test doesn't pass because execute() method returns responses before coroutine are finished

There was 1 failure:

1) CsvRowProcessorTest::should_process_csv_row
Failed asserting that actual size 0 matches expected size 4.

Is there some technique to handle this scenario?

Among other things, I was expecting a second problem which, however, is not happening. I was expecting where to run coroutines within a context but this problem is not reported. It simply fails the assertion

matyhtf commented 3 years ago

Use Coroutine\run in the test function, And use WaitGroup to wait for all coroutines to finish executing.

https://www.swoole.co.uk/docs/modules/swoole-coroutine-waitgroup