PHPUnit 8, how to set dynamically set testdox description - phpunit

I'm using #testdox annotation in PHPUnit 8 to set the description for my tests.
This works fine, but I'd like to be able to set the description dynamically. A method like this would be nice:
$this->setTestDoxDescription("My super test routine for date: ".$mydate->format('Y-m-d');
I have tests that check the results of various date-related functions. Many of the tests are relative to today's date, so the input date values are not fixed and are generated dynamically. I would like to be able to print the date values in the description.
I just discovered the setName() method in TestCase and it seems to do mostly what I want:
$this->setName("My super test routine for date: ".$mydate->format('Y-m-d');
However, there is some kind of parsing and it is splitting my dates on - chars and adding extra spaces. For example, 2020-04-04 is changed to 2020- 04- 04. But if I use #testdox 2020-04-04 it does not split things. It is only a problem when I use setName(). Not a big deal, but kind of annoying.
I've solved my problem for now, but maybe someone can recommend a better way.

You can put variable names into the #testdox string, the variables that are being returned from the #dataprovider (given as the method parameters).
An example from phpunit's own tests...
/**
* #testdox Valid regex $pattern on $subject returns $return
* #dataProvider validRegexpProvider
*
* ....
*/
public function testValidRegex($pattern, $subject, $return): void
I've just added it to my own tests and one dataprovider/testdox output example is:
#testdox displayNumber formats $input as '$expectedLong' & '$expectedShort'
public function testNumber($input, $expectedLong, $expectedShort): void {}
✔ displayNumber formats 1781234 as '1,781,234' & '1.8M'

Related

Entity expected object returned symfony

I'm trying to get an item from the database and pass it to a new item to push to the database.
$post = $entityManager->getRepository('App:Post')
->find($id);
$comment->setPost($post)
the setPost looks like the following:
public function setPost(Post $post): self
{
$this->post = $post;
return $this;
}
and the $post variable:
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Post", inversedBy="comments")
* #ORM\JoinColumn(nullable=false)
*/
private $post;
But when i try to set the post like setPost($post) it gives me the following error:
Expected parameter of type '\App\Entity\Post', 'object' provided
I assume, that the error you see is from your integrated developent environment (IDE), for example eclipse, vs code, phpstorm, and others. But the code - when actually executed - should work.
Now, the error most likely stems from a static code analysis running in the background of said IDE, which will look at the statement and trying to analyze according to the called methods, accessed properties etc. of which type your variables are.
So, let's do this slowly (and you can probably hover over the $vars and ->methods() do verify. The line I'm interested in is
$post = $entityManager->getRepository('App:Post')
->find($id);
so $entityManager is of type EntityManagerInterface, which has a getRepository method with one required parameter of type string ('App:Post' in your case), and it will return an object of type ObjectRepository, which has a method find which requires one parameter (mixed, don't ask), and returns ?object which means, an object or null. So, $post is of type object (best case, or null, in which case it would fail!). Now, the next line obviously expects a parameter of type Post and not of type object, thus the warning/notice/error.
Now, static code analysis is quite helpful up to a certain level, but it isn't infallible because it has limitations. It doesn't know what runtime will actually return, it just assumes that the type hints found in the code (of doctrine) are sufficiently specific - which they aren't in your case.
the easy fix
add a doc string to tell static code analysis what the variable $post's type actually is:
/** #var Post $post */
$post = $entityManager->getRepository('App:Post')
->find($id);
this explicitly tells the static analysis tool, that $post is of type Post, maybe you have to write App\Entity\Post or even \App\Entity\Post.
the hard fix
Alternatively, you could implement your own PostRepository (doctrine provides some help) and define a function like function findById($id) :Post - which would explicitly tell static code analysis, what the return type is when you call it in your code (injected in your function via dependency injection: PostRepostory $postRepository):
$post = $postRepository->findById($id);
If you're using lots and lots of different entities, this is a very verbose solution but depending on your project it might be worth it, since you explicitly name the dependencies instead of injecting the very unspecific (as we have seen) EntityManagerInterface. Using the EntityManagerInterface might make testing HELL (imho!).

Where is a definitive guide for rewriting my test classes in the face of setMethods() deprecation?

MockBuilder::setMethods() method got deprecated in 8.3, but examples in the documentation still use it, and I can't find a definitive migration guide anywhere. Does one exist?
Out of respect for your time potentially spent writing an answer: answers boiling down to "just keep using setMethods(), it still works" will not be accepted.
setMethods() has been deprecated as of this PR
At this moment of the time documentation are outdated but I guess they will be fixed in no time. To answer your question about setMethods it has been replaced with two new functions
onlyMethods
/**
* Specifies the subset of methods to mock, requiring each to exist in the class
*
* #param string[] $methods
*
* #throws RuntimeException
*/
public function onlyMethods(array $methods): self
{...}
addMethods
/**
* Specifies methods that don't exist in the class which you want to mock
*
* #param string[] $methods
*
* #throws RuntimeException
*/
public function addMethods(array $methods): self
{...}
Example
Old Code might have looked like this
$merchant = $this->getMockBuilder('\Fake\FakeMerchant')
->setMethods(['getLegalEntity'])
->getMock();
which should be now like this
$merchant = $this->getMockBuilder('\Fake\FakeMerchant')
->addMethods(['getLegalEntity'])
->getMock();
Extra Information
I didn't find the definitive migration guide but since I recently
had to migrate from old phpunit 4.x to new phpunit 8.4 here are the tips that you can follow.
PHPUnit_Framework_TestCase has been replaced with PHPUnit\Framework\TestCase
PHPUnit_Framework_MockObject_MockObject has been replaced with PHPUnit\Framework\MockObject\MockObject
->getMock has been removed. So the alternative is either ->createMock(), createPartialMock or ->getMockBuilder()->getMock()
Functions like setUp setUpBeforeClass, tearDown, etc now need to define ::void return type
mockObject->setMethods is deprecated and should be replaced with onlyMethod for method that already exists and addMethods for methods that does exists on the class
#expectedException from docblock is deprecated and $this->setExpectedException has been removed

Symfony 4 - Set DateTime

so I've been following this Database and the Doctrine tutorial: https://symfony.com/doc/current/doctrine.html
the only difference is that I added a created_ts field to it (among some other fields, but they work fine so no need to go into them).
I used the make:entity command to generate my class and the method for setting my created_ts got generated like this:
public function setCreatedTs(\DateTimeInterface $created_ts): self
{
$this->created_ts = $created_ts;
return $this;
}
So in my /index page I went to save a new entity using:
$category->setCreatedTs(\DateTimeInterface::class, $date);
I had a funny feeling this would error and I was right:
Type error: Argument 1 passed to App\Entity\Category::setCreatedTs() must implement interface DateTimeInterface, string given
but I'm not sure how to implement the DateTimeInterface inside the function.. I tried googling but it shows a lot of Symfony2 posts, a few I tried to no avail.
How do I set a datetime value in my entity from the ->set method?
(if there is already an answer, please link. #symfonyScrub)
update
# tried doing this:
$dateImmutable = \DateTime::createFromFormat('Y-m-d H:i:s', strtotime('now')); # also tried using \DateTimeImmutable
$category->setCategoryName('PHP');
$category->setCategoryBio('This is a category for PHP');
$category->setApproved(1);
$category->setGuruId(1);
$category->setCreatedTs($dateImmutable); # changes error from about a string to bool
If your date is the current date, you can just do this:
$category->setCreatedTs(new \DateTime())
Your first error was caused by the strtotime function that returns a timestamp but the \DateTime constructor was expecting a Y-m-d H:i:s format.
That's why instead of creating a valid \DateTime, it returned false.
Even if it's unnecessary in this case, you should have done something like this to create a \DateTime based on a timestamp:
$date = new \DateTime('#'.strtotime('now'));

Getting the current module name

Is there a way to get the name of the module you are working within? I have a large set of modules (about 35) with some common functionality. Long story short is that I would like to be able to get the module name without hard-coding it in a string. Hopefully this isn't necessary, but here's an idea of what I'm trying for:
function MYMODULE_mycustom_hook($args) {
$sCurrModule = 'MYMODULE';
// Operations using $sCurrModule...
}
Essentially, I can replace 'MYMODULE' with the module name and be done with it, but I'm wondering if there is a way to get that value programmatically. I'm using Drupal 7.
This does not apply to Drupal 8.
If your module file is sites/default/modules/MYMODULE/MYMODULE.module then module name is MYMODULE.
You can get it programmatically inside MYMODULE.module file using following command:
$module_name = basename(__FILE__, '.module');
Although OP was asking regarding D7, here's the solution for Drupal 8 (D8) as well:
/** #var \Drupal\Core\Extension\ModuleHandlerInterface $module_handler */
$module_handler = \Drupal::service('module_handler');
/** #var \Drupal\Core\Extension\Extension $module_object */
$module_object = $module_handler->getModule(basename(__FILE__, '.module'));
$module_name = $module_object->getName();
Of course, you can chain these calls if necessary:
\Drupal::service('module_handler')->getModule(basename(__FILE__, '.module'))->getName()
As correctly said in comments
basename(__FILE__, '.module');
only works inside an actual .module file.
Answering to question:
inside your MYMODULE.module
function print_current_module_name() {
return basename(__FILE__, '.module');
}
from everywhere in Drupal >8
$module_name = print_current_module_name();
echo "module name is : " . $module_name
Not sure this will work on Drupal 7 as well

Are there docblox in R?

When writing PHP in Netbeans, as long as I provide my functions and classes with "docblox", Netbeans will show what parameters a function expects, what it will return, and a short description whenever I go to call it somewhere else. There is also the benefit of using it for automatically generated API documentation with a tool such as PHPDocumentor2. Is there any kind of equivalent in R? Currently I'm developing in RStudio.
Example of a docblox in PHP:
/**
* This is the description of some function
*
* #param string $foo A foo string
* #return string Foo string in all caps
*/
function cap_foo($foo) { return strtoupper($foo); }
Is docblox the commented part? If so, check roxygen2

Resources