3

I am attempting to use Zend_Test_PHPUnit_ControllerTestCase in my testing and am experiencing difficulties.

My application bootstrap instantiates a library class that manages access to a Zend_Session_Namespace called 'LiveData'. LiveData maintains arrays of data for Current User, Current Organsation, etc. Once instantiated, the LiveData object is stored in the registry.

When I instantiate LiveData, I set singleInstance = true, ie. new Zend_Session_Namespace('LiveData', true) This is to reduce potential confusion about who does what to LiveData.

Anyhow, this seems to work fine. I browse the site, login, logout, etc, and my session data behaves as I would expect.

When trying to test, however, I get a message saying "A session namespace object already exists for this namespace".

My tests are bootstrapped in each test file as follows:

public function setUp()
{
    $this->bootstrap = new Zend_Application(APPLICATION_ENV, 
            APPLICATION_PATH . '/configs/application.ini');
    parent::setUp();
}

This was the default scaffolding placed there by Netbeans. Reading the Zend_Test documentation, this seems fine to me.

The problem seems to arise when I dispatch a controller in a test, as follows:

public function testIndexIsDefaultAction()
{
    $this->dispatch('/');

    // assertions
    $this->assertController('Index');
    $this->assertAction('index');
}

I think that the test's setUp() method is resulting in my application bootstrap running (and creating a copy of LiveData). Then $this->dispatch('/') is running the bootsrap again... I can't imagine why this would be the case, though. (Why would we want it to run twice?) If you can shed any light on my plight, I'd be most appreciative!

1 Answer 1

2

The setUp() method only tells Zend how to call your bootstrap which is done when you call dispatch(). However, your bootstrap will be run for every test method. Since you're telling Zend to prevent multiple instances of Zend_Session_Namespace with the same namespace, the second test method will fail.

Look in the source for Zend_Session_Namespace for a way to reset the flag. If it exists, add it to your test bootstrap before you call your application bootstrap.

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

5 Comments

Thanks David. Right you are. I've removed the flag for now and put it on the to-do list. This raises a larger question for me about the 'theory of operation' of Zend and PHPUnit. I'll try to put it into another SO question.
Yes, each test method is treated as a new request just as if it had come in from index.php to the front controller. You need to make sure that anything you do in the bootstrap can either be cleared or doesn't block a second call to it from succeeding.
That's helpful to know, though I'm still not 100% clear on how Zend and PHPUnit interact. I could understand PHPUnit persisting its own state, or the state of the application its testing. It doesn't seem right to me that system under test would persist its state between test methods (in the same way that it doesn't persist between calls made via index.php, unless it deliberately persisted in a Zend_Session et al object).
Under normal operations each request from the browser that hits index.php occurs in a separate system process. All of the objects created during the previous request are deleted from memory and a new PHP process is started. When running tests in PHPUnit, all tests are run in the same process one after the other. This leaves all the objects that Zend created lying about, and the flag that tells it not to allow the same namespace to be created again is stored in a static (essentially global) variable that doesn't get cleared.
You can run each test in a separate process using the --process-isolation flag to PHPUnit, but they will run much slower. Better to find ways to clear any global state left behind between tests.

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.