-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Make export of objects customizable #5758
Comments
Configurable on the test suite level (in the XML configuration file) or on the test level (using an attribute)? |
Ideally it should be on project level, e.g. install a plugin to phpunit. |
My current problems, to be precise are these:
|
Similar problem that happened previously: #5524 |
Correct me if I'm wrong, but what you are asking for can already be achieved using a custom comparator: <?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use SebastianBergmann\Comparator\Comparator;
use SebastianBergmann\Comparator\ComparisonFailure;
final class C
{
private array $data;
public function __construct(array $data)
{
$this->data = $data;
}
public function largeDataStructure(): array
{
return $this->data;
}
}
final class Test extends TestCase
{
public function testOne(): void
{
$this->registerComparator(
new class extends Comparator
{
public function accepts(mixed $expected, mixed $actual): bool
{
return true;
}
public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false): void
{
$expectedAsString = 'foo';
$actualAsString = 'bar';
throw new ComparisonFailure(
$expected,
$actual,
$expectedAsString,
$actualAsString,
'Failed asserting that ...',
);
}
}
);
$a = new C([1, 2, 3]);
$b = new C([4, 5, 6]);
$this->assertEquals($a, $b);
}
} Of course, you can also "simplify" |
Actually I think I have considered that solution (I've looked extensively through the source code since 9.5), but found something lacking. What if I wan't to compare, throughout my project, complex data structures (arrays, objects, etc.) which might or might not contain things I'd want to simplify on various levels thoughout the given structure. This means I need to a) recreate the original equality comparer from scratch, or b) somehow use it for everything but the complicated objects, which gets incredibly difficult. Am I making any sense to you? |
Not really, sorry. Maybe this helps: |
I get your point. Lets consider an example. Say that I want a custom string representation of the class $a = new Apple(3);
$b = new Apple(5);
self::assertEquals($a, $b); Imagine then I have this code: self::assertEquals(
[
'key1' => 10,
'key2' => new Apple(5),
'key3' => [,
'key3.1' => 'string 1',
'key3.2' => new Apple(7),
],
],
getDataStructure(),
); Will then my comparer be called for keys |
No. |
See my point? If I compare data structures that contain the objects I need to use my comparer on, it won't be called and the default textual representation is used. So using a custom comparer has a very limited application even if it is a workaround in these cases. But this gets us back to the original point - we don't really care about the comparing. What we care about is the textual representation. P.S. It would be nice to be able to have a custom comparer that works in all cases though. Say, for example, if the equality comparer works on type level - for every value compared get the relevant comparer and when there are containers (arrays/colletions of values or objects with properties), the relevant container is called for each property/key type. But that's a different subject. P.P.S. I'd be happy to contribute when time permits if you're open to the idea we're discussing. |
This is a complex topic that I am uncomfortable with delegating and I will look into this when I find the time. |
I completely understand that. Given that you probably don't have enough time, what if I told you it would be completely okay if you decided to completely throw away my work at the end? I can explain my idea of doing it, probably do some prototyping and I won't mind if you decide my work sucks at the end. (Imagine how bad I need this 🤣😂🤣) |
as I stumbled over this today when running the test-suite of roave/BetterReflection:
|
I know, @staabm. It is not easy to tackle, though. As far as I understand it, though, the most problematic That being said, I am willing to make |
I also think thats the main problem. is this data only used for showing it to the human looking at the phpunit result output? |
I am working on a proof-of-concept that may already be "good enough", hope to have it in a shareable state soon. |
At least I fixed the performance problem in PHPStan by passing around plain strings instead: phpstan/phpstan-src@da87a65 |
I think this could be as simple as #5773. |
@BladeMF was the primary motivation for this issue really that you want to implement exporter methods for certain objects or is your actual primary concern only in the inefficient performance of the out-of-the-box export? I am wondering whether we really need the configurable export, or whether just a more efficient export would already cover all your concerns. |
@staabm I can try and outline my problems chronologically:
|
@BladeMF Thank you for explaining your use case(s). What do you think about sebastianbergmann/exporter#56? The idea is similar to #5773, but instead of completely swapping out |
Yes, I really like that implementation. I left just one comment explaining what an example implementation of my exporter would look like. |
@sebastianbergmann BTW, thank you for your work. If not for |
How should we understand that removal from 11.3 milestone? Is this not planned anymore? |
The
Exporter
that provides text representation of arguments and assertions. There are, however, really big objects which are not practical to be displayed (e.g. Doctrine entities, Phpstan test case arguments). Since the actualExporter
class is not injected and is not an interface, its behaviour cannot be modified. If I have a test that is asserting equality between two Doctrine entities and it fails, the displayed error is hundreds of screens long and not practical.It should be possible to decorate the default export and modify its behaviour without that affecting anything in Phpunit. That way one can create plugins that print certain large objects properly - doctrine and phpstan included.
The text was updated successfully, but these errors were encountered: