admin管理员组

文章数量:1316829

I need to run tests on a certain class, but adding a method that was not originally present.

Previously this need could be satisfied using MockBuilder::addMethods(), but this method has been deprecated.

So, currently, the simplest alternatives are to define (somewhere) a new class or to use an anonymous class, which extends the class affected by the test and implements the new method.

In my case, I extend the DropdownHelper class by adding the (non-existent in the original) getLastLink() method:

$Dropdown = new class (new View()) extends DropdownHelper {
   public function getLastLink(): string
   {
      return $this->_links ? end($this->_links) : '';
   }
};

Now the problem is calling

$Dropdown->getLastLink()

phpstan gives me this error:

Call to an undefined method Climat\Core\View\Helper\DropdownHelper::getLastLink().

How can I properly document this? I would like to avoid defining another class elsewhere and using the anonymous one (and I would like to avoid suppressing the error, but rather document the anonymous class correctly).

Thanks.


EDIT

I close for my mistake.

In fact, trying a simpler and stupider example:

<?php

class First {
    public function methodFromTheFirstClass(): void {}
}

$Second = new class extends First {
    public function methodFromTheSecondClass(): void {}
};

$Second->methodFromTheFirstClass();
$Second->methodFromTheSecondClass();

the error does not appear and is not replicable.

So, necessarily, the problem is specifically related to the single class with which I am interacting (even if, as specified, the anonymous class and the method call are on the same scope).

Thanks and sorry.

I need to run tests on a certain class, but adding a method that was not originally present.

Previously this need could be satisfied using MockBuilder::addMethods(), but this method has been deprecated.

So, currently, the simplest alternatives are to define (somewhere) a new class or to use an anonymous class, which extends the class affected by the test and implements the new method.

In my case, I extend the DropdownHelper class by adding the (non-existent in the original) getLastLink() method:

$Dropdown = new class (new View()) extends DropdownHelper {
   public function getLastLink(): string
   {
      return $this->_links ? end($this->_links) : '';
   }
};

Now the problem is calling

$Dropdown->getLastLink()

phpstan gives me this error:

Call to an undefined method Climat\Core\View\Helper\DropdownHelper::getLastLink().

How can I properly document this? I would like to avoid defining another class elsewhere and using the anonymous one (and I would like to avoid suppressing the error, but rather document the anonymous class correctly).

Thanks.


EDIT

I close for my mistake.

In fact, trying a simpler and stupider example:

<?php

class First {
    public function methodFromTheFirstClass(): void {}
}

$Second = new class extends First {
    public function methodFromTheSecondClass(): void {}
};

$Second->methodFromTheFirstClass();
$Second->methodFromTheSecondClass();

the error does not appear and is not replicable.

So, necessarily, the problem is specifically related to the single class with which I am interacting (even if, as specified, the anonymous class and the method call are on the same scope).

Thanks and sorry.

Share Improve this question edited Jan 29 at 14:41 Mirko Pagliai asked Jan 29 at 10:06 Mirko PagliaiMirko Pagliai 1,2501 gold badge19 silver badges36 bronze badges 6
  • If the method is not present in a class...it shouldn't be tested! Either extend the class explicitly or define a trait, or use composition. Can you provide a concrete use case? – moonwave99 Commented Jan 29 at 10:28
  • @moonwave99 I know that the method should not be tested, I need it as a workaround to test something else (but as it was for addMethods()). I can describe the concrete use case (I think it's simpler): the $_links property is not otherwise accessible (and it's an array and I need the last value). Other alternatives would be to implement a "get" method or use ReflectionProperty. I would like to avoid modifying the original class and understand if it is possible to avoid somewhat "cumbersome" workarounds (in short, I know some solutions, I would like to understand which is the best method) – Mirko Pagliai Commented Jan 29 at 10:36
  • 1 Is the $Dropdown = new class definition in the same scope as the $Dropdown->getLastLink() call? If it is, it feels rather like a bug/limitation in PHPStan, because it's incorrectly identified $Dropdown as of type DropdownHelper, rather than as a sub-class with an extra method. If it's not, what's the type declaration of the parameter where $Dropdown is passed - because that's what PHPStan will be analysing? – IMSoP Commented Jan 29 at 11:32
  • @IMSoP yes, they have the same scope. and yes, he believes that ‘$Dropdown‘ is a normal instance of ’DropdownHelper‘. if it's possible that it's a bug or a limitation, then in the meantime I'll open an issue on their repository – Mirko Pagliai Commented Jan 29 at 12:14
  • @MirkoPagliai private fields should not be accessible from outside (that's the whole point of making them private!). It looks like you are doing some integration tests - what feature of the software are you testing? If for instance it is rendering some HTML, check that the link you added appears in the markup at the right position, etc...but rely on the contract of the class and not on its internals! – moonwave99 Commented Jan 29 at 13:08
 |  Show 1 more comment

1 Answer 1

Reset to default 2

Best to add an interface. Let the anonymous class implement the interface and let the method returning the anonymous class typehint that interface.

本文标签: phpHow to describe anonymous classes and methodsStack Overflow