5

Maybe the question comes across as weird, but here is the problem that I'm trying to solve... first of all, please keep in mind I am more of a Java developer getting used to working with PHP, so maybe my thought process is the problem!

I am testing a web site that I have built with Symfony. For my component testing, I create my test class extending WebTestCase and my test I have a set of assertions like the following to verify that the page title is where I want it and containing what I expect:

$text = "Page Title";
$selector = "h2#pageHeading";
$this->assertEquals(1, $crawler->filter($selector)->count(), "Found wrong number of elements using selector ".$selector);
$this->assertEquals(trim($text),
        trim($crawler->filter($selector)->text()),
        "Element $selector didn't have expected text");

Then I write more tests for other pages within the site, and in all of them I want to test the title is there as it should be, so to be able to reuse code I refactor the above into a function in parent class that the other test classes reuse:

function assertPageTitle($text) {
    $selector = "h2#pageHeading";
    $this->assertEquals(1, $crawler->filter($selector)->count(), "Found wrong number of elements using selector ".$selector);
    $this->assertEquals(trim($text),
            trim($crawler->filter($selector)->text()),
            "Element $selector didn't have expected text");
}

And I call that method in my tests. As tests develop there are more similar "complex assertions" that I can refactor, and all of them go to the parent class, thus bloating my parent class into a massive assertion container:

protected function assertSelectedOptionContainsTextValue($selector, $text, $value, $crawler) {
    ...
}

protected function assertMenusContainItems($menus, $crawler) {
    ...
}

protected function assertErrorMessageShown($message, $crawler) {
    ...
}

... (more and more) ...

You get the idea. My next thought at this point is to refactor all this "complex assertions" into other classes, probably following the Page Object pattern, but then the other classes won't have access to the assertEquals method unless those other classes also extend WebTestCase or at least PHPUnit_Framework_TestCase, which doesn't seem a very good idea...

So is there an easy way to access the assertEquals method (and related) without having to extend the base PHPUnit classes? Can I use composition somehow?

2
  • You really should be using seleniumif you want to test your UI code. phpunit.de/manual/current/en/selenium.html Commented Jan 23, 2015 at 18:26
  • 1
    I'm not quite sure I would agree with that. Selenium is slow and flaky, prone to fail for mysterious reasons. We use Selenium where PHP Tests don't reach, but just that. Commented Jan 24, 2015 at 19:49

3 Answers 3

14

PHPUnit's built-in assertions are implemented as public static methods in the PHPUnit_Framework_Assert class. Just invoke them as PHPUnit_Framework_Assert::assertTrue(), for instance.

Sign up to request clarification or add additional context in comments.

1 Comment

Good point. Actually, even though I'm going I'm applying @user2970075's suggestion, this is definitely closer to an answer to my original question. I'll mark it as so. Thanks!
2

First of all, you are overwriting $text variable at the beginning of your "generic" function - but I understand that you want to only show idea.

Secondly, using unit testing to this kind of tests isn't the best choose. I think you should extract logic of titles to separated classes and then test it by PHPUnit or use more appropriate testing solutions like Behat or Selenium.

If you still haven't changed your opinion... You must extend at least PHPUnit_Framework_TestCase whenever you want to use PHPUnit to testing.

Little hint: Traits would be good to extract your assertions.

2 Comments

Thanks for pointing out the typo in the code, corrected now. I was trying to avoid extending PHPUnit_Framework_TestCase maybe because I'm thinking in Java (where you can just import the assertions and use them). The choice of Traits sounds interesting, but it seems to be available from 5.4.0 and I'm stuck with 5.3.24 :(
So I think you should change your mindset :) There is no better way to do that.
0

In order to create reusable phpunit assertion in trait. That can be used in many tests cases. You can use trait that statically calls PHPUnit_Framework_Assert::assertSame, quick example how to achieve it:

<?php

namespace Tests\Foo;

use PHPUnit_Framework_Assert;

trait AssertTrait
{
    public function assertInTraitAlwaysFailing()
    {
        PHPUnit_Framework_Assert::assertSame(1, 2, 'always failing');
    }
}

It would act as helper that can be used in many places where you need same assertion to prevent duplication.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.