Problem/Motivation

Currently assertCacheContexts relies on the return value of assertIdentical. Let's rewrite it to not do that,
so it works on BrowserTestBase as well.

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Comments

dawehner created an issue. See original summary.

dawehner’s picture

martin107’s picture

Assigned: Unassigned » martin107

Looking at AssertPageCacheContextsAndTagsTrait for other similar problems

The use of $this->assertIdentical() needs to be removed from assertCacheTags() also

martin107’s picture

Assigned: martin107 » Unassigned
Status: Active » Needs review
StatusFileSize
new1.39 KB

Less unintended coupling - that is a good idea.

I need to signal a slight change is behaviour

previously if assertCacheContext were called with a NULL message then a default message would be constructed inside assertIdentical.

to see this message post patch, we have to rely on the debug function call to see that information. - but that follows the convention setup in the rest of the trait.

dawehner’s picture

  1. +++ b/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php
    @@ -128,7 +128,7 @@ protected function assertCacheTags(array $expected_tags, $include_default_tags =
    -    $this->assertIdentical($actual_tags, $expected_tags);
    +    $this->assert($actual_tags === $expected_tags);
         $this->debugCacheTags($actual_tags, $expected_tags);
       }
    

    Yeah we don't need to change this one.

  2. +++ b/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php
    @@ -159,7 +159,7 @@ protected function assertCacheContexts(array $expected_contexts, $message = NULL
    -    $return = $this->assertIdentical($actual_contexts, $expected_contexts, $message);
    +    $return = assert($actual_contexts === $expected_contexts, $message);
    

    Is there a reason why you don't use $this->assert()? assert() is something else.

martin107’s picture

StatusFileSize
new3.55 KB

belatedly, I agree with #5.

Conventionally methods of the form assertXYZ() don't return a bool

So the next step is to just to assert and not return a boolean.

This has consequences for code that used to make use of the bool.

ToolbarCacheContextsTest::assertToolbarCacheContexts()

Thankfully the chain ends there and nothing uses the return value from assertToolbarCacheContexts()

I have preserved the message - daisy chaining but since there are two assert in assertToolbarCacheContexts the (human) debugger needs to know which point failed.
so I have added a suffix to the message if it is passed in.

-- Did I go too far?

Status: Needs review » Needs work

The last submitted patch, 6: assert-2795579-6.patch, failed testing.

dawehner’s picture

IMHO we don't really have to adapt toolbar test. When we return FALSE in WTB land, we would directly throw the exception in BTB land and no longer have to care about anything. Given that we can always assume that those return TRUE basically.

Do you understand what I mean with that?

martin107’s picture

Status: Needs work » Needs review
StatusFileSize
new1.1 KB

Regarding toolbar tests.... as you wish.

In the next patch I have inserted a Variable name change:- $return becomes $match.

We are actively using it in the method, and I would rather the name have semantic value, and then also happen to be the variable we return.

In relation to #5

Is there a reason why you don't use $this->assert()? assert() is something else.

It is a matter of coupling... looking inside the original call the assertIdentical() - it made use of asser().... Ahem I was just copying
.
$this->assert() implies extending WebAssert, the errors I created in #6 stem from this.

For example look at this stirng of classes
CommentRssTest -- CommentTestBase -- Drupal\simpletest\WebTestBase

At the moment this version of WebTestBase in the string does not pick up webAssert so no assert() and the test fail with a fatal.

In your little unofficial initiative - will this be resolved by other issues?

I'm sorry my knowledge is not wide enough to answer this question.

For the moment I am going to leave the assert() in and post a patch, and say I will be happy to adjust, accordingly.

Maybe we should postpone until other issues resolve the problem?

dawehner’s picture

At the moment this version of WebTestBase in the string does not pick up webAssert so no assert() and the test fail with a fatal.

Ah I see what you mean. What about the following:

a) Keep your code with the debug() call
b) Keep the assertion:

-    $return = $this->assertIdentical($actual_contexts, $expected_contexts, $message);

c) When $return === NULL (which is the BTB case), return TRUE.

With that we should have a working version in both BTB and WTB.

What do you think about that?

martin107’s picture

StatusFileSize
new1.27 KB

That works - I am adding documentation - because the next coder along may be confused initially.

Also I want to be careful to "get the cart before the horse" [ I seem to remember there is a similar idiom in german :) ]

In short we have to make the comparison twice - because under failure conditions we have a call to assert in assertIdentical() and I want the debug to show first.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

" [ I seem to remember there is a similar idiom in german :) ]

There indeed is.

Nice work!

klausi’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/modules/system/src/Tests/Cache/AssertPageCacheContextsAndTagsTrait.php
@@ -159,12 +159,16 @@ protected function assertCacheContexts(array $expected_contexts, $message = NULL
+
+    // For compatibility with both BrowserTestBase and WebTestBase always return a boolean.
+    return ($return === NULL) ? TRUE : $return;

comments should wrap at 80 characters. Also the comment is wrong, we don't always return a boolean.

Should be "For compatibility with both BrowserTestBase and WebTestBase only return a boolean for WebTestBase."

Which also means we need to adapt the @return docs of this method, right?

Which sounds overly complicated. I think it is fine to always return a boolean, nobody using BrowserTestBase will care.

dawehner’s picture

Which sounds overly complicated. I think it is fine to always return a boolean, nobody using BrowserTestBase will care.

So you argue to not return a boolean for BTB? I thought we keep the existing behaviour and always return a boolean, also for BTB and call it a day.

klausi’s picture

Yes, always return a boolean and not do this complicated NULL handling in the current patch.

dawehner’s picture

Yes, always return a boolean and not do this complicated NULL handling in the current patch.

Well, how would you do that? The BTB version of assertIdentical returns NULL. The WTB version returns a boolean, we actually want to return.

klausi’s picture

We can just return the $return variable that is explicitly being prepared in the patch.

martin107’s picture

I don't follow your logic.

if the output of assertIdentical() in some configurations returns null - and the value is used to create $return

how is this compatible with "yes, always return a boolean" ( #15)

klausi’s picture

Status: Needs work » Needs review
StatusFileSize
new1.68 KB
new1.45 KB

Sorry, I meant just return the $match variable like this.

tstoeckler’s picture

The BTB version of assertIdentical returns NULL.

That's a pretty clear bug, no?

It's very important that assert*() methods return booleans. It's not done very much in core sadly, but good (TM) tests generally fail gracefully, which assert*() methods make very easy if they return booleans.

The following test code, for example, may fail, but it will never fatal:

if ($this->assertInstanceOf($object, $class)) {
  $this->assertSomething($object->someMethodOnClass());
}

Whereas if you can't/don't rely on the return value of assert*() and just do

$this->assertInstanceOf($object, $class);
$this->assertSomething($object->someMethodOnClass());

your test will still never pass incorrectly, but it may fatal which is annoying from a CI/test runner/test logs perspective.

X-Post with @klausi: I think the last patch is a lot more elegant than previous versions, but should I open a separate ticket for the above?

martin107’s picture

Ah --- that makes the code simpler.

Klausi++

klausi’s picture

With the move to phpunit we are going to remove return values of assert*() methods to be consistent with phpunit core which never returns anything on assertions.

Fatal errors are fine, since phpunit as a testrunnner can properly deal with them.

The big difference in phpunit is that assertions throw exceptions when they fail. Which means as soon as one assertion fails the test case is finished and will not be continued.

dawehner’s picture

klausi++

dawehner’s picture

Status: Needs review » Reviewed & tested by the community
tstoeckler’s picture

Ahh, yes had totally forgotten that point about PHPUnit, you're right. So my point above is moot. That has always bugged me a lot about PHPUnit, but whatever...

RTBC++

alexpott’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: +rc eligible

Since this is a test only change - and also makes no functional change - I think this is RC eligible.

Committed and pushed 52f2a29 to 8.3.x and 7ff6bb5 to 8.2.x. Thanks!

  • alexpott committed 52f2a29 on 8.3.x
    Issue #2795579 by martin107, klausi, dawehner: Adapt assertCacheContexts...

  • alexpott committed 7ff6bb5 on 8.2.x
    Issue #2795579 by martin107, klausi, dawehner: Adapt assertCacheContexts...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.