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

neclimdul created an issue. See original summary.

neclimdul’s picture

Status: Active » Needs review
StatusFileSize
new7.91 KB

Something like this maybe. Quick pass on unit tests only as they where easy to test.

Status: Needs review » Needs work

The last submitted patch, 2: 2934701-setExpectedAssertion.patch, failed testing. View results

neclimdul’s picture

Status: Needs work » Needs review

Failures where the intermittent disk space issues. back to NR.

neclimdul’s picture

Version: 8.5.x-dev » 8.6.x-dev
StatusFileSize
new7.87 KB

per 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.

Aki Tendo’s picture

When 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.

neclimdul’s picture

Agree'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.

Aki Tendo’s picture

No 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.

neclimdul’s picture

StatusFileSize
new7.86 KB

from other issue:

diff --git a/core/tests/Drupal/Tests/AssertHelperTrait.php b/core/tests/Drupal/Tests/AssertHelperTrait.php
index ba814d9641..1ea613c390 100644
+ protected function expectAssertion($message = '') {
+ if (ini_get('zend.assertions') != 1) {

This needs to be > 0 like all the others I think.

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.

neclimdul’s picture

interdiff...

Aki Tendo’s picture

I'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.

neclimdul’s picture

I believe all feedback has been addressed. Is there something that I could do to move this forward?

neclimdul’s picture

Issue summary: View changes
StatusFileSize
new2.19 KB
new8.7 KB

One 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.

rodrigoaguilera’s picture

Status: Needs review » Needs work

if (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) {

neclimdul’s picture

Status: Needs work » Needs review
StatusFileSize
new8.7 KB
new1.36 KB

sure. manually tested with -1,0,1 and this seems to work as expected

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

jhedstrom’s picture

I 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.

jhedstrom’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

The patch no longer applies, so needs a reroll.

+++ b/core/tests/Drupal/Tests/Component/Utility/HtmlTest.php
@@ -343,7 +343,12 @@ public function testTransformRootRelativeUrlsToAbsolute($html, $scheme_and_host,
+    if (ini_get('zend.assertions') <= 0) {
+      $this->markTestSkipped(
+        'Assertions are not enabled. Set zend.assertions to 1 to run this test.'
+      );
+    }
+    elseif (method_exists($this, 'expectException')) {
       $this->expectException(\AssertionError::class);

Can't this use the trait as well?

ravi.kiran’s picture

StatusFileSize
new1.28 KB

Re-rolled patch in #15 against 8.9.x

ravi.kiran’s picture

Status: Needs work » Needs review
jungle’s picture

RTBC +1

neclimdul’s picture

Version: 8.9.x-dev » 9.0.x-dev
Status: Needs review » Reviewed & tested by the community
StatusFileSize
new3.59 KB
new2.77 KB

Here'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

neclimdul’s picture

StatusFileSize
new10.43 KB

bah, wrong patch...

xjm’s picture

Version: 9.0.x-dev » 9.1.x-dev
alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/tests/Drupal/Tests/AssertHelperTrait.php
@@ -32,4 +32,24 @@ protected static function castSafeStrings($value) {
+    if (ini_get('zend.assertions') <= 0) {
+      $this->markTestSkipped(
+        'Assertions are not enabled. Set zend.assertions to 1 to run this test.'
+      );
+    }

It'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:

    <env name="zend.assertion" value="1"/>
    <env name="assert.active" value="1"/>

to core/phpunit.xml.dist and document that these are required for running the core test suite.

neclimdul’s picture

StatusFileSize
new11.14 KB

Nice! Thanks for the review, good feedback hitting some gaps in the discussion so far.

So I was totally on board with testing assert.active but when I got to your last point I realized _why_ it was written this way ages ago. So see my comments on that below. :)

Having yet another test helper for people have to learn

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 1 or 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.assertions at runtime since <ini> is just wrapping ini_set it 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.

neclimdul’s picture

Status: Needs work » Needs review
kapilv’s picture

I am facing a similar problem. after the apply #28 patch, test running successfully, thanks

Aki Tendo’s picture

Hi 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:

/**
 * @requires setting zend.assertions 1
 */

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.

Aki Tendo’s picture

Assigned: Unassigned » Aki Tendo
Status: Needs review » Active
StatusFileSize
new7.52 KB

Ok, 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.

Aki Tendo’s picture

Issue summary: View changes
Aki Tendo’s picture

Issue summary: View changes
neclimdul’s picture

Issue tags: -Needs reroll

Yeah 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

    $this->expectAssertion('assert(strpos($data_type, \'entity:\') !== 0 || $this instanceof EntityContextDefinition)');

is a lot better than

    $this->expectException(\AssertionError::class);
    $this->expectExceptionMessage('assert(strpos($data_type, \'entity:\') !== 0 || $this instanceof EntityContextDefinition)');

but Alex didn't seem keen on it in #27

Aki Tendo’s picture

I 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.

neclimdul’s picture

Good 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.

alexpott’s picture

Category: Feature request » Task
Status: Active » Needs review

This new implementation is now a task.

  1. +++ b/core/tests/Drupal/Tests/UnitTestCase.php
    @@ -20,6 +20,7 @@
    +  use AssertHelperTrait;
    

    This is not needed - doesn't exist anymore.

  2. The patch should also include
    +++ b/core/phpunit.xml.dist
    @@ -17,6 +17,8 @@
    +    <!-- Do our best to make sure assertions behave as expected. We can't change zend.assertions though. -->
    +    <ini name="assert.active" value="1"/>
    

    In the core/phpunit.xml.dist

  3. RE the assert helper - we need less helpers not more. It's more for people to learn. PHPUnit changes fast so this increases maintenance burden. PHPUnit moved away for a single method for asserting the exception class and message for whatever reason. Adding it back in Drupal and only for a special case feels like a step in wrong direction.
Aki Tendo’s picture

Rather 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.

neclimdul’s picture

you can ini_set the value right?setting the environment value would just set the default value. Enforce the assumption tests are currently working under.

Aki Tendo’s picture

That'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).

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new176 bytes

The 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.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.