Problem/Motivation
There are now multiple tests in Drupal which use runtime assertions to aid coders during development. These tests will fail if zend.assertions is set to 0 or -1. There is no way to specify or change this value during runtime so we can't force the correct version of the value so users are left without a clear reason why they can't run the core test suite.
Proposed resolution
As of version 8.5 PHP Unit provides a @requires setting annotation that can check the value of zend.assertions and skip the test if it isn't set to 1.
Remaining tasks
Reviews
User interface changes
n/a
API changes
None.
Data model changes
n/a
Testing
Testing can be done easily with the phpunit runner. Just add the following code to your phpunit.xml.dist file in the <php> section.
<!-- Force assertions to expected value. -->
<ini name="zend.assertions" value="0"/>
Comments
Comment #2
neclimdulSomething like this maybe. Quick pass on unit tests only as they where easy to test.
Comment #4
neclimdulFailures where the intermittent disk space issues. back to NR.
Comment #5
neclimdulper discussion on #2936802: expectDeprecation() doesn't work in isolated tests, prefer PhpUnit 6 method naming convention.
Rerolled against 8.6.x since its open and this is a feature but there shouldn't really be a reason not to backport this testing DX improvement.
Comment #6
Aki Tendo commentedWhen I have some time I'll compare the tests changed in this patch against the tests changed in #2916440 (which is now marked as related to this) - there's bound to be some overlap, if not a lot of overlap.
I want to get us to a point where we can freely run all tests with assertions on or off. Tests which check assertions will be skipped as seen in the patch for the related issue.
I've also submitted a request to the PHPUnit team to add an annotation that can be used to check zend.assertions (or any other ini setting) before running a test, and skipping the test if the required value isn't set.
EDIT: I've reviewed the patch - there is indeed an almost complete overlap between the patch here and the one in the issue I raised a few months ago.
Comment #7
neclimdulAgree'd on the clean run and sorry about the overlap.
I believe I discussed this with alexpott somewhere about the fact that specific ini setting can't be tested in a annotation like modules and other things which is why this was the solution. I'd be interested in following what's happening upstream as we'll probably want to adjust what ever we do towards matching their solution as move forward though even if such a annotation existed this would be useful semantic sugar.
Comment #8
Aki Tendo commentedNo need to apologize over the overlap. Indeed, I feel guilty for not being a squeakier wheel on this to get the related patch included sooner. No one's to blame though - there's just so much to do that some things will sometimes go through cracks, but I did do a promote to crit on #2916440 to try to keep it from falling through the cracks again.
Comment #9
neclimdulfrom other issue:
zend.assertions currently only has -1, 0, and 1 as valid values but there's no harm I can think of at the moment in allowing for larger values to trigger this behavior.
Comment #10
neclimdulinterdiff...
Comment #11
Aki Tendo commentedI'm not married to either one, and maybe the strict op of !== would be the most sound, but whichever is used should be used consistently.
Comment #12
neclimdulI believe all feedback has been addressed. Is there something that I could do to move this forward?
Comment #13
neclimdulOne thing would be that the patch actually did what it said... we want to skip when assertions are set to 0.
Fix the assertion check.
Replace a new assertion since this patch was written.
Documented how to test in the IS as well.
Comment #14
rodrigoaguileraif (ini_get('zend.assertions') == 0) {I read the conversation but I did not get why this is also not skipping when zend.assertions = -1
Is the default for the php debian package for example.
I feel the best check would be
if (ini_get('zend.assertions') <= 0) {Comment #15
neclimdulsure. manually tested with -1,0,1 and this seems to work as expected
Comment #19
jhedstromI closed #2714595: Improve failures for tests requiring assert() when its not enabled as a duplicate of this one as they appeared to be approaching the same issue, and this one was more recent.
Comment #20
jhedstromThe patch no longer applies, so needs a reroll.
Can't this use the trait as well?
Comment #21
ravi.kiran commentedRe-rolled patch in #15 against 8.9.x
Comment #22
ravi.kiran commentedComment #23
jungleRTBC +1
Comment #24
neclimdulHere's a reroll with the converted assertions that where all conflicting.
Interdiff includes the changes:
- some new assertions that had been added
- a fix to the message parameter. It was suppose to be asserting the message not a message about the assertion. Matched optional to other core usage as well.
- Removal of the old setExpectedException compatibility code since 9 doesn't support that anymore and the rest of 8 was converted away from it a long time ago (most of the conflicts)
@jungle feel free to move it to RTBC :-D
Comment #25
neclimdulbah, wrong patch...
Comment #26
xjmComment #27
alexpottIt's not only about this setting it's also about assert.active. If that's set to 0 these test are going to fail too.
Also I'm not sure this is a good solution. Having yet another test helper for people have to learn exists feels the wrong way around.
Also I've got to ask but what is being proved by running core's unit tests in another environment? I'm missing the point and value to the community. Our unit tests are not API, they're not meant to prove any custom code works, and they're not meant to validate an environment.
The sole value of doing this is if you're working on an issue that changes one of these tests and it's failing for this reason for you locally. And for me that suggests that we should add:
to core/phpunit.xml.dist and document that these are required for running the core test suite.
Comment #28
neclimdulNice! Thanks for the review, good feedback hitting some gaps in the discussion so far.
So I was totally on board with testing
assert.activebut when I got to your last point I realized _why_ it was written this way ages ago. So see my comments on that below. :)Yeah I mean ideally phpunit would had better tools for interacting with assertion but it doesn't. I don't think testing with them is just that common so we can't
@require_ini zend.assertion 1or something which is what lead to this workaround. Historically these sort of short comings are the sort of things we address in traits and base classes in our test suite so I think it makes sense. This method is arguably better as well. Its self documenting so it reads easier by sayings what its testing and you don't have to remember how to assert the assertion or remember the exception name etc. I'd wager most people just grep for that place its done elsewhere and copy/paste... I know I do.As far as environments, I think its about developer experience not environments. Should developers have this on? Absolutely. But we do use @requires to skip and improve the feedback to developers that don't have an extension installed when a test runs. Skipping just gives better feedback and explicit messaging... or it does in phpunit and probably someday in core's test runner to... not sure the state of those patches.
On a personal level, I always end up back at this issue because I changed the value for some reason or was setting up a new environment or something and spent like an hour hunting through the routing system or equally complex system trying to figure out why the values going into an assert where wrong. I mean I just changed some logic in the theme system for crying out loud! Only to realize the error is something entirely different. You'd think I'd learn but it seems like its always just long enough that I've forgotten. "Not thrown" because assertions are off is the same as "not thrown" because the value is wrong in the eyes of the test and we just hang developers out in the wind to figure that out for themselves. :( :(
As far as the phpunit.xml.dist change, that's a really good suggestion. It totally improves the developer experience and should address the same problem. I don't see any discussion about it in this issue but the problem is you can't change actually do that . Or at least you can't change
zend.assertionsat runtime since<ini>is just wrappingini_setit can't handle that. That's why the patch is only testing zend.assertions but why not force the expected value of assert.active and then we don't have to worry about it? Sounds good to me! Patch doing that attached.Comment #29
neclimdulComment #30
kapilv commentedI am facing a similar problem. after the apply #28 patch, test running successfully, thanks
Comment #31
Aki Tendo commentedHi all. Getting back up to speed having spent the last couple years pulled into Java and JavaScript projects.
Before I got pulled away I submitted a pull request to the PHP Unit project which was included 2 years ago that significantly affects this project. As of PHP Unit 8.5 (at least, maybe older) individual tests can be annotated to run only when assertions are turned on, or turned off. This is the format:
Leveraging this annotation to the tests requiring it is cleaner than applying this patch.
Note also the patch I submitted to the PHP Unit project can be used against any PHP setting. I used display_errors in the unit test of the unit test in PHP Unit since that can be changed at runtime.
EDIT: For some reason @requires setting isn't in PHP Unit's documentation. I need to inquire with Mr. Bergman as to why - but most likely it's an oversight. In any event the implementing code in PHP Unit is present.
Comment #32
Aki Tendo commentedOk, Here's a complete rebuild that leverages the annotation above. It should be possible to backport to 9.0.x if it is also using PHPUnit 8.5 or higher.
Comment #33
Aki Tendo commentedComment #34
Aki Tendo commentedComment #35
neclimdulYeah I thought I'd checked that when I picked this issue back up. Glad it was undocumented and I hadn't lost my mind :)
Seems like we can keep the "assert.active" setting change to phpunit.
I still think the DX of
is a lot better than
but Alex didn't seem keen on it in #27
Comment #36
Aki Tendo commentedI have about 2 years worth of changes to get up to speed on so I didn't consider the ramifications of the code changes. I just took the code as it and applied the required setting annotation to the functions that appeared in the patch without modifying their code. I did carry over the use assert trait change from the patch as it is harmless if not actually needed.
As to the DX of writing runtime assertion checks - the only only time a runtime assertion should be tested by a unit test is if it part of a public API. Modules that aren't creating new API's shouldn't need to have any unit tests against their runtime assertions. So, while it does come up, it shouldn't come up often.
Anyway, I'm trying to get my current employer to use Drupal instead of making yet another proprietary in house CMS. Wish me luck - if I succeed I should have more time for core contribs.
Comment #37
neclimdulGood Luck!
That's a fair point. As long as this has been floating around I'd like to get the assertion helper in before it gets pigeon holed, but lets just wrap up this up with the @requires and the phpunit.xml environment helper. Since those seem to be no brainers. I'll open up a follow up with some of the other assertion helper discussions going on.
Comment #38
alexpottThis new implementation is now a task.
This is not needed - doesn't exist anymore.
In the core/phpunit.xml.dist
Comment #39
Aki Tendo commentedRather than have assert.active always be on, wouldn't it be better to set assert.active to the value of zend.assertions > 0 ?
This way units can be ran with assert in both modes if that is deemed necessary for any reason in the future.
Comment #40
neclimdulyou can
ini_setthe value right?setting the environment value would just set the default value. Enforce the assumption tests are currently working under.Comment #41
Aki Tendo commentedThat's what I mean - assert.active can be set at runtime, zend.assertions can't. So why don't we have our PHPUnit bootstrap lock assert.active to the value of zend.assertions > 0 and be done with it. That way we aren't tracking two very similar and somewhat confusing switches.
(Reminder, the difference between 0 and -1 is that 0 emulates how PHP 5 behaved, running any function call appearing as an argument to an assert statement even if assertions are turned off, which is not how assertions are really supposed to work. -1 skips the line and anything called by the line entirely - it doesn't even get compiled in).
Comment #47
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.