Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHPUnit Test Support #13

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft

PHPUnit Test Support #13

wants to merge 7 commits into from

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

Co-authored-by: Caleb White <cdwhite3@pm.me>
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.

2 participants