Question

I have a test suite that used to work perfectly well. It is based on FWOpenCartTest, a big descendant of PHPUnit_Framework_TestCase implementing a MVC framework (based on OpenCart).

Today I had to add to such descendant a call instantiating another class which internally allocates a var stream as follows:

    // register a variable stream wrapper
    require_once( DIR_SYSTEM . 'library/variable_stream.php' );
    $ok = stream_wrapper_register("var", "VariableStream");
    if (!$ok) {
        trigger_error("Failed to register protocol for a variable stream");
        exit;
    }

Since then, I can't run any test, as I keep getting PHPUnit dumps like:

phpunit ControllerAccountWishListTest.php
PHP Warning:  stream_wrapper_register(): Protocol var:// is already defined. in /var/www/domain.tld/public_html/system/engine/factory.php on line 73
PHP Stack trace:
PHP   1. {main}() /usr/bin/phpunit:0
PHP   2. PHPUnit_TextUI_Command::main() /usr/bin/phpunit:46
PHP   3. PHPUnit_TextUI_Command->run() /usr/share/php/PHPUnit/TextUI/Command.php:129
PHP   4. PHPUnit_Runner_BaseTestRunner->getTest() /usr/share/php/PHPUnit/TextUI/Command.php:150
PHP   5. PHPUnit_Framework_TestSuite->__construct() /usr/share/php/PHPUnit/Runner/BaseTestRunner.php:142
PHP   6. PHPUnit_Framework_TestSuite->addTestMethod() /usr/share/php/PHPUnit/Framework/TestSuite.php:212
PHP   7. PHPUnit_Framework_TestSuite::createTest() /usr/share/php/PHPUnit/Framework/TestSuite.php:834
PHP   8. FWOpenCartTest->__construct() /usr/share/php/PHPUnit/Framework/TestSuite.php:473
PHP   9. Factory->__construct() /var/www/domain.tld/public_html/unittests/VisualPHPUnit/app/test/opencart/FW_OpenCartTest.php:41
PHP  10. stream_wrapper_register() /var/www/domain.tld/public_html/system/engine/factory.php:73
PHP Notice:  Failed to register protocol for a variable stream in /var/www/domain.tld/public_html/system/engine/factory.php on line 75
PHP Stack trace:
PHP   1. {main}() /usr/bin/phpunit:0
PHP   2. PHPUnit_TextUI_Command::main() /usr/bin/phpunit:46
PHP   3. PHPUnit_TextUI_Command->run() /usr/share/php/PHPUnit/TextUI/Command.php:129
PHP   4. PHPUnit_Runner_BaseTestRunner->getTest() /usr/share/php/PHPUnit/TextUI/Command.php:150
PHP   5. PHPUnit_Framework_TestSuite->__construct() /usr/share/php/PHPUnit/Runner/BaseTestRunner.php:142
PHP   6. PHPUnit_Framework_TestSuite->addTestMethod() /usr/share/php/PHPUnit/Framework/TestSuite.php:212
PHP   7. PHPUnit_Framework_TestSuite::createTest() /usr/share/php/PHPUnit/Framework/TestSuite.php:834
PHP   8. FWOpenCartTest->__construct() /usr/share/php/PHPUnit/Framework/TestSuite.php:473
PHP   9. Factory->__construct() /var/www/domain.tld/public_html/unittests/VisualPHPUnit/app/test/opencart/FW_OpenCartTest.php:41
PHP  10. trigger_error() /var/www/domain.tld/public_html/system/engine/factory.php:75

Here's the little test that causes the error:

<?php

require_once('FW_OpenCartTest.php');

class ControllerAccountWishListTest extends FWOpenCartTest {
    public function testTheContentsOfALoggedInCustomersWishList() {
        $controller = $this->loadControllerByRoute("account/wishlist");

            $this->customerLogin('username@domain.tld','9a24b01674');
            $controller->index();

            $this->assertEquals(1, preg_match('/Your wish list is empty./', $this->getOutput()));
    }
}

?>

What I am asking for is: is this an interaction between PHPUnit and the test case class FWOpenCartTest?

The completed application works, if I don't use PHPUnit but just create a wrapper to instantiate the test it also works.

If there's an interaction, is there any way to hide the stream_wrapper_register() so that FWOpenCartTest's constructor won't find it assigned already?

Was it helpful?

Solution

This is how I have fixed my own, personal situation with this isse. It's not meant to be THE one way for everybody.

Premise: How I got here

This question came as a consequence of me installing a very useful OpenCart Testing Suite. I loved it because if you have to heavily customize OpenCart it will really help keeping the whole project under control. In fact it's easy to cause unintended side consequences when customizing such a large MVC framework. This becomes even more important, because OpenCart does not natively implement "retail developer friendly" extensions / addons hooks like i.e. WordPress or Drupal. Therefore most professional OpenCart developers install third party extension engines, usually VQMod and OpenCart Override Engine.

How to make the tests work

Once installed the Testing Suite, you would inherit your own OpenCart installation customization. In my case, the unit tests are meant to apply to my own code so I don't need a 1:1 faithful installation snapshot. In this I am lucky, because Override Engine's factory class does not play nicely with PHPUnit at all. Both want to use a var stream and this creates a nasty conflict: even forcing PHPUnit and Override Engine to use the same stream, one of them will call unsupported functions and will cause PHP errors.

Therefore what I have done is to

1) Revert my Override Engine modified OpenCart installation's root index.php back to the original distribution file. However I kept my own customizations.

The following screenshot shows me looking at the differences between the two index.php files. On the left there's the new version I am "restoring" back to the original, to the right there's the currently installed, Override Engine version based on its factory class.

Edit: sadly I don't have the "rep" to put in pictures so here's the link.

2) Alter the restored index.php with the Override Engine modifications. In my case I replaced the default cache instancing code with my own version. Basically, you'd manually include your file(s) from the Override Engine directories and instance them in place of the default classes.

3) If needed, you have to write mock objects / members to let the test suite run.

Example of how to run OpenCart vs PHPUnit compliant code meant to be ran with Override Engine.

Phase 1: Find the Override Engine "converted" code in the Unit Test Case's index.php:

// Cache
$cache = $factory->newCache();
$registry->set('cache', $cache);

Phase 2: Restore the Unit Test Case's index.php statement(s) to the original OpenCart version:

// Cache
$cache = new Cache();
$this->registry->set('cache', $cache);

Phase 3: Manually apply the classes you have overridden and / or provide mock objects

// Cache
// $cache = new Cache();
require_once (OVERRIDE_ENGINE_ROOT . 'mymods/system/library/cache.php');
$cache =  new MyMods_Custom_Cache();
$this->registry->set('cache', $cache);

That's as close to getting to a solution done as I could get.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top