Giter VIP home page Giter VIP logo

phpunit-util's Introduction

amphp/phpunit-util

AMPHP is a collection of event-driven libraries for PHP designed with fibers and concurrency in mind. amphp/phpunit-util is a small helper package to ease testing with PHPUnit.

License

Installation

This package can be installed as a Composer dependency.

composer require --dev amphp/phpunit-util

The package requires PHP 8.1 or later.

Usage

<?php

namespace Foo;

use Amp\ByteStream;
use Amp\PHPUnit\AsyncTestCase;
use Amp\Socket;

class BarTest extends AsyncTestCase
{
    // Each test case is executed as a coroutine and checked to run to completion
    public function test(): void
    {
        $socket = Socket\connect('tcp://localhost:12345');
        $socket->write('foobar');

        $this->assertSame('foobar', ByteStream\buffer($socket));
    }
}

phpunit-util's People

Contributors

bwoebi avatar cspray avatar kelunik avatar remorhaz avatar trowski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

phpunit-util's Issues

The docs example test is left waiting indefinitely

๐Ÿ‘‹ Hi there,

At ChesslaBlab we're writing functional tests for the PHP Chess Server.

See:

At this moment I'm trying to run the docs example as it is shown in the two images below.

tab_01
Figure 1. php cli/testing.php

tab_02
Figure 2. vendor/bin/phpunit tests/functional/

However, the test is left waiting indefinitely.

<?php

namespace ChessServer\Tests\Functional;

use Amp\ByteStream;
use Amp\PHPUnit\AsyncTestCase;
use Amp\Socket;

class StartCommandTest extends AsyncTestCase
{
    public function test(): void
    {
        $socket = Socket\connect('tcp://127.0.0.1:8080');
        
        $socket->write('/start classical fen');

        $expected = '{"\/start":{"variant":"classical","mode":"fen","fen":"rnbqkbnr\/pppppppp\/8\/8\/8\/8\/PPPPPPPP\/RNBQKBNR w KQkq -"}}';

        $this->assertSame($expected, ByteStream\buffer($socket));
    }
}

Also this is the cli/testing.php script running the TCP socket server on port 8080 shown in Figure 1.

<?php

namespace ChessServer\Cli;

use ChessServer\Socket\TcpSocket;
use Dotenv\Dotenv;

require __DIR__ . '/../vendor/autoload.php';

$dotenv = Dotenv::createImmutable(__DIR__.'/../');
$dotenv->load();

$server = new TcpSocket($_ENV['TCP_PORT']);

Any help would be greatly appreciated.

Thank you,

[RFC] AsynchronousTestCase and TestContext

Thank you for the excellent work that you've done to improve asynchronous programming in PHP. I am starting to develop a series of applications on top of amphp and I plan on developing a series of test utilities that I wanted to see if you'd like to see added to this library.

The first piece is an AsynchronousTestCase that would allow userland code to ensure all asynchronous operations in their test completes appropriately and that tests aren't allowed to run forever. This is accomplished by allowing tests to return a Promise to control when the test ends and setting a delay timer to ensure the test does not run past a set period of time.

The second is a TestContext class (or something more aptly named) that would ensure a series of asynchronous tasks occur and to also act as a Deferred able to provide a Promise returned for each test in the AsyncTestCase.

Here is a gist of an example implementation of the AsyncTestCase along with an example test using the TestContext object. https://gist.github.com/cspray/88ce3d550a0e5ac74c5cafbc5b85df95

Please let me know if you have any questions or any other feedback. If this is something that you would be interested in I can provide tests for it (nothing like testing the tests) and submit a PR. Before I go down that route I wanted to ensure this is something you'd like to see.

Thanks

Implement with trait instead of base class

It is common for PHPUnit extensions to implement functionality with base classes, but we can only extend one. Therefore, it is often impossible to use two or more extensions at once. For example, one may wish to use Symfony's WebTestCase but also AsyncTestCase, which is impossible since both must be extended directly.

Since traits offer unlimited extension, an alternative implementation should be offered in addition to/instead of the current base class approach.

TestCase::expectException() does not detect exceptions in AsyncTestCase

I'm working on a simple abstraction built on top of http-server for making async APIs and I ran into the following issue - when I try to write a test to assert that an exception is thrown, TestCase::expectException() seems to be unaware of it actually happening. Take a look at this snippet:

<?php
class AwesomeTest extends AsyncTestCase
{
    public function testOhNoes()
    {
        $this->expectException(Error::class);
    
        yield call(function () {
            throw new Error;
        });
    }

    public function testYay()
    {
        $this->expectException(Error::class);

        throw new Error;
    }
}

And the output from PHPUnit:

1) AwesomeTest::testOhNoes
Error: 
/home/jakobmats/workspace/empress/test/AwesomeTest.php:13
/home/jakobmats/workspace/empress/vendor/amphp/amp/lib/functions.php:60
/home/jakobmats/workspace/empress/test/AwesomeTest.php:14
/home/jakobmats/workspace/empress/vendor/amphp/amp/lib/Coroutine.php:60
/home/jakobmats/workspace/empress/vendor/amphp/amp/lib/functions.php:66
/home/jakobmats/workspace/empress/vendor/amphp/phpunit-util/src/AsyncTestCase.php:23
/home/jakobmats/.config/composer/vendor/phpunit/phpunit/src/TextUI/Command.php:201
/home/jakobmats/.config/composer/vendor/phpunit/phpunit/src/TextUI/Command.php:160

The other test case passes without problems. Any ideas why it happens? As far as I understand it the error should bubble up until it hits the top level so that PHPUnit is supposed to see it, no?

Uncaught exception in a test method hangs it

Shoulnd't it abort the loop instead?

Same happens if we just remove the line throw new Exception("TEST");, but I'm not sure whether it's so by design.

class MyAsyncTestCase extends AsyncTestCase
{
    function test()
    {
        Loop::repeat(1000, static function() { echo "alive\n"; });
        throw new Exception("TEST"); // Doesn't abort the loop. This method runs forever.
    }
}

Loop runs forever

I have a TCP connection running in the event loop. This TCP connection has always something to do, like handling heart beats. I need to explicitly close the connection, otherwise the loop will run forever and never stop.

I used wait(call(...)) before and there wasn't this problem. Using phpunit-util, I need to close the connection manually and add that line of code more than 400 test cases. Is there a way around this that can be incorporated into this lib?

RFC: Refactoring to support PHPUnit 10

PHPUnit 10 has recently been released and it includes improvements to the testing framework along with a new Event system. Unfortunately, it also brings along a breaking change that causes this library to no longer work. Specifically, the PHPUnit\Framework\TestCase::setName method has been marked as final and can no longer be overridden. Fortunately, I believe the event system could simplify what we'd have to do.

A tl;dr is that we create an Extension that invokes EventLoop::getSuspension()->suspend() in an appropriate event. The first thought is the PHPUnit\Event\Events\Test\Finished event.

If this sounds like a good place to start I can work on a new branch for PHPUnit 10 support in the next week or two.

Mocking a class without a mocked method that would normally return a promise causes the loop to stop without resolving the test

For example:

<?php

use Amp\PHPUnit\AsyncTestCase;
use Amp\Success;
use Generator;

class MockedClass {
    public function doSomething(): Promise {
        return new Success('Some Value');
    }
}

class TestedClass {

    private MockedClass $mockedClass;

    public function __construct(MockedClass $mockedClass) {
        $this->mockedClass = $mockedClass;
    }

    public function performAction(): Promise
    {
        // Not the greatest example..
        return new Success( yield $this->mockedClass->doSomething() );
    }
}

class TestedClassTest extends AsyncTestCase {
    public function testPerformAction() {
        $mockedClass = $this->createMock(MockedClass::CLASS);
        $testedClass = new TestedClass($mockedClass);

        yield $testedClass->performAction();

        $this->assertEquals(1, 1);  // Is never reached.
    }
}

Causes: Loop stopped without resolving promise or coroutine returned from test method

If you define the method mock which is yielded inside TestedClass to return a promise, it works.

Caused a fair bit of confusion writing tests, wouldn't mind an easier to understand error message if possible!

PHPUnit 7

Hi,
PHPUnit 7 is not supported currently, any blockers? I would provide PR, but there are no tests unfortunately (can you add some please?).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.