0

My test fails when I use $this->at(0) instead of $this->once(). I am surely missing a point here, but I don't know what. Anyone knows what could that be?

/**
 * Passes
 */
public function testOne()
{
    $expected = array(
        'id' => 1,
        'name' => 'Product Name'
    );

    $mock = $this->getMock('WS');
    $mock->expects($this->once())
        ->method('getProductInfo')
        ->with($this->equalTo(1))
        ->will($this->returnValue($expected));

    $this->object->setWs($mock);

    // same as $mock->getInfo(1)
    $returned = $this->object->getWs()->getProductInfo(1);
    $this->assertEquals($expected, $returned);
}

/**
 * Fails
 */
public function testOne()
{
    $expected = array(
        'id' => 1,
        'name' => 'Product Name'
    );

    $mock = $this->getMock('WS');
    $mock->expects($this->at(0)) // all that changed
        ->method('getProductInfo')
        ->with($this->equalTo(1))
        ->will($this->returnValue($expected));

    $this->object->setWs($mock);

    // returned equals NULL
    // same as $mock->getInfo(1)
    $returned = $this->object->getWs()->getProductInfo(1);
    $this->assertEquals($expected, $returned);
}   
edorian
  • 38,542
  • 15
  • 125
  • 143
Marcelo
  • 1,702
  • 2
  • 24
  • 42

1 Answers1

1

I can only guess as I can't look into setWs but the only difference is that ->at(0) always tries to match the FIRST function call the to mock object and maybe the constructor of WS already calls something (as an example).

As i can't say anything more concrete without a executable test case maybe something general:

With the current capabilities of the PHPUnit Mocking API there is no need to every use ->at(0). Everything I've seen that uses ->at() can now be expressed more nicely using ->will($this->logicalOr(...) together with ->returnCallback() or ->returnValueMap(). See this example for at vs returnCallback

So if you don't have a use case where you specifically NEED(!) to make sure the method calls are in the right oder I wouldn't worry about it :)


Basic ->at example that works, just in case

<?php

class ClassToTest
{
    public function willGetCalled($value) {}
}

class TestClass extends PHPUnit_Framework_TestCase
{
    public function testWithExplicitMock()
    {   
        $mock = $this->getMock(
            'ClassToTest'
        );  

        $mock->expects($this->at(0))
            ->method('willGetCalled')
            ->with(5);

        $mock->willGetCalled(5);
    }   
}
Community
  • 1
  • 1
edorian
  • 38,542
  • 15
  • 125
  • 143
  • 1
    Hey edorian, thank you for your response. However, the ws constructor wont call the expected method, cause if so, once() would have failed. I need the ->at(0) method because i need to test a ->at(1) situation (same method, different args, different response). Anyway, I am gonna take a look at that logicalOr. That may be helpful. Thank you very much! – Marcelo Dec 06 '11 at 13:05
  • @Marcelo Check out the link to the sample I've edited in on how you can do that without using ->at() and why that might be better. If that doesn't work out maybe expand your question with something i can execute to figure it out :) – edorian Dec 06 '11 at 13:11
  • I had seen your response on that topic. I based my [yet to be a] solution on that. That is exactly what I need, but that is still not working =/. I filter/paste my code in a few minutes. Thank you again for your help :) – Marcelo Dec 06 '11 at 13:24
  • Great! A simpler version of my class worked as expected. I guess it means something else is messy. =/ https://gist.github.com/1438292 – Marcelo Dec 06 '11 at 14:00
  • Im closing this topic since I've done something stupid, although i dont know what. Thank you @edorian. You really helped me :) – Marcelo Dec 06 '11 at 14:17