Skip to content

Conversation

@V13Axel
Copy link
Owner

@V13Axel V13Axel commented Jun 12, 2024

The goal of this PR is to add support for running PHPUnit tests. Who knows what that'll look like though.

@V13Axel
Copy link
Owner Author

V13Axel commented Jun 12, 2024

So far I'm not 100% sure this possible at the moment for one reason: Identifying tests is hard. Specifically, due to what (at first, cursory glance) appears to be differences in the way Pest runs PHPUnit tests compared to standard vanilla PHPUnit.

In short, this adapter (and the neotest-phpunit adapter) parses the XML output of the --log-junit flag for PHPUnit in order to determine the outcome of the tests, and the output is not incredibly helpful.

I created a very simple test file for this:

<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        $this->assertTrue(true);
    }
}

Then I placed that in tests/Unit on two different projects: One setup for PHPUnit and the other setup for Pest.


Vanilla PHPUnit

Running phpunit --log-junit=storage/app/examplelog.xml --filter=ExampleTest, here's the contents of storage/app/examplelog.xml

<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite name="/var/task/phpunit.xml" tests="1" assertions="1" errors="0" failures="0" skipped="0" time="0.001678">
    <testsuite name="Unit" tests="1" assertions="1" errors="0" failures="0" skipped="0" time="0.001678">
      <testsuite name="Tests\Unit\ExampleTest" file="/var/task/tests/Unit/ExampleTest.php" tests="1" assertions="1" errors="0" failures="0" skipped="0" time="0.001678">
        <testcase name="testBasicTest" file="/var/task/tests/Unit/ExampleTest.php" line="14" class="Tests\Unit\ExampleTest" classname="Tests.Unit.ExampleTest" assertions="1" time="0.001678"/>
      </testsuite>
    </testsuite>
  </testsuite>
</testsuites>

Looks like we have everything we need in order to determine exactly where that test is, on disk: File name, test case method name, line number... It's all there.


However, if we compare that against the same ExampleTest file, but run through Pest instead:

<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite name="Tests\Unit\ExampleTest" file="Example (Tests\Unit\Example)" tests="1" assertions="1" errors="0" failures="0" skipped="0" time="0.001652">
    <testcase name="Basic test" file="Example (Tests\Unit\Example)::Basic test" class="Tests\Unit\ExampleTest" classname="Tests.Unit.ExampleTest" assertions="1" time="0.001652"/>
  </testsuite>
</testsuites>

The "file" attribute is no longer the file path, but instead ClassName (ClassPath). There is a testcase name, though! So not all hope is lost, I think.


However, here's what neotest provides as the 'position' data to evaluate when discovering tests, from which the adapter has to create a unique identifier:

{
    name = "testBasicTest",
    path = "/home/axel/Git/neotest-pest/tests/Unit/ExampleTest.php",
    range = { 13, 4, 16, 5 },
    type = "test"
}

I have to use that data to create an ID. Then, I have to use the data from the XML to create that same ID so I can match up test <-> result.

It almost feels like all the data I need is there, but needs reformatting. I'm not 100% confident, but I think the adapter can make some assumptions and wind up with something workable.

@V13Axel V13Axel mentioned this pull request Jun 12, 2024
Comment on lines 4 to 17

use PHPUnit\Framework\TestCase;

class ExamplePhpunitTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testBasicTest()
{
$this->assertTrue(true);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a heads up that PHPUnit also supports the following methods of declaring a method to be tests (they have to be public of course):

Suggested change
use PHPUnit\Framework\TestCase;
class ExamplePhpunitTest extends TestCase
{
/**
* A basic test example.
*
* @return void
*/
public function testBasicTest()
{
$this->assertTrue(true);
}
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
class ExamplePhpunitTest extends TestCase
{
public function testBasicTest(): void
{
$this->assertTrue(true);
}
/** @test */
public function itAssertsTrue(): void
{
$this->assertTrue(true);
}
#[Test]
public function itAssertsTrueAgain(): void
{
$this->assertTrue(true);
}

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've gone ahead and committed this suggestion, but I am reasonably certain that this branch won't work with the latter two at the moment. It may detect - and even run - the tests, but I don't think results will be matched properly off-hand

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants