3

I am doing some PHPUnit testing with symfony2. I am having a problem with one particular test.

I am testing a response form one of my Class of course one response is true one false. I have a Mock of my Database and I have a stub for one of the methods from my databaseRepository.

The issue is that in one test I do a stub to a method with an valid array, second test i just want to query to be invalid null.

my db MOck:

    //Setting up mock of database repository class
    $this->db = $this->getMockBuilder('DatabaseRepository')
        ->disableOriginalConstructor()
        ->getMock();

    $this->db->expects($this->any())
        ->method('getRecord')
        ->will($this->returnValue(self::$registrationRecord));

    $this->db->expects($this->any())
        ->method('getRecord')
        ->willReturn(null);

So I am trying to have two different expects but this obviousley does not work.....is it possible to have a stub method to have two different returns..?

test1:

    <?php


class UnsubscribeRegistrationTemplateTest extends \PHPUnit_Framework_TestCase
{

    /**
     * @var UnsubscribeRegistrationTemplate
     */
    protected $object;

    /**
     * @var ValidationClass
     */
    public $validate;

    /**
     * @var DatabaseRepository
     */
    public $db;

    //Database Record Mock
    public static $registrationRecord = array
    (
        'rowid' => '96',
        'unsubscription' => 'N',
        'updated' => 'BB'
    );

    /**
     *
     */
    protected function setUp()
    {
        //Setting up mock of validation class
        $this->validate = $this->getMockBuilder('ValidationClass')
            ->disableOriginalConstructor()
            ->getMock();

        $this->validate->expects($this->any())
            ->method('validateInput')
            ->willReturn(true);

        //Setting up mock of database repository class
        $this->db = $this->getMockBuilder('DatabaseRepository')
            ->disableOriginalConstructor()
            ->getMock();

        $this->db->expects($this->any())
            ->method('getRegistrationRecord')
            ->will($this->returnValue(self::$registrationRecord));

        $this->db->expects($this->any())
            ->method('getRegistrationRecord')
            ->will($this->returnValue(null));

        $this->db->expects($this->any())
            ->method('setPreRegistrationEnquiryUnsubscriptionEnabled')
            ->willReturn(true);

        $this->object = $this->createUnsubscribeRegistrationTemplateInstance();
    }

    /**
     * @return UnsubscribeRegistrationTemplate
     *
     */
    public function createUnsubscribeRegistrationTemplateInstance()
    {
        //initialize Unsubscribe Registration Template
        return new UnsubscribeRegistrationTemplate
        (
            $this->validate,
            $this->db
        );
    }

    /**
     * @param array $mapping
     * @return Request
     */
    public function createRequest(array $mapping)
    {
        $request = new Request();

        foreach ( $mapping as $k =>$v)
        {
            $request->query->set($k, $v);
        }

        return $request;
    }

    /**
     *
     */
    public function testUnsubscribeRegistrationTemplateValidResponse()
    {
        $request = $this->createRequest(array(
            'registration_id' => '96',
            'source_channel' => 'BB'
        ));

        $response = new Response(
            true,
            'Unsubscription successful'
        );

        $this->assertEquals($response, $this->object->create($request));
    }

    /**
     *
     */
    public function testUnsubscribeRegistrationTemplateEmptyResponse()
    {
        $request = $this->createRequest(array(
            'registration_id' => '96',
            'source_channel' => 'BB'
        ));

        $response = new Response(
            false,
            'Registration Record Not Found.'
        );

        $this->assertEquals($response, $this->object->create($request));
    }

    /**
     *
     */
    public function testIsAlreadyRegisteredValidResponse()
    {
        //Testing record is already unsubscribed
        $registrationRecord = array(
            'unsubscription_enabled' => 'Y'
        );

        $this->assertTrue($this->object->isAlreadyUnsubscribed($registrationRecord));
    }

    /**
     *
     */
    public function testIsAlreadyRegisteredInValidResponse()
    {
        //Testing record not unsubscribed
        $registrationRecord = array(
            'unsubscription_enabled' => 'N'
        );
        $this->assertFalse($this->object->isAlreadyUnsubscribed($registrationRecord));
    }

    /**
     *
     */
    protected function tearDown()
    {
        unset($this->object);
    }

}
5
  • move the expect in the relative test method, as example, if testIsAlreadyRegisteredInValidResponse want that getRecord return null, move the code there and remove the other expect from setup. Commented Jun 9, 2015 at 9:38
  • yes I was doing this before but the expect function was getting highlighted by my PhpStorm and i though it will not work so never even boathered to try :/ now i did and it works perfect but php storm hihglights it saying: Method expect not found in class databaseRepository Commented Jun 9, 2015 at 9:52
  • Don't worry about it, is only because phpstorm don't undestand the correct object type probably due a wrong or missing PHPDoc annotation. So you solved? Commented Jun 9, 2015 at 9:55
  • yes i did thx up voted it but in all fairness @Pierre Marichez mentioned this form the start Commented Jun 9, 2015 at 10:00
  • 1
    of course, Pierre immediately understand what problem do you have. The important is that you fixed the problem and... you learn how better use the testing framework! Commented Jun 9, 2015 at 10:02

2 Answers 2

3

You can do this in many ways.
Here are two ways that may suits your needs.

1 - Move the getRecord() expects to the tests

/**
* @test
*/
public function ifTrue()
{
    $this->db->expects($this->once())
    ->method('getRecord')
    ->will($this->returnValue(self::$registrationRecord));

    $request = $this->createRequest(array(
        'id' => '10',
        'code' => 'BB'
    ));

    $response = new Response(
        true,
        'successful'
    );

    $this->assertEquals($response, $this->object->create($request));
}

/**
 * @test
 */
public function ifFalse()
{
    $this->db->expects($this->once())
    ->method('getRecord')
    ->willReturn(null);

    $request = $this->createRequest(array(
        'id' => '10',
        'code' => 'BB'
    ));

    $response = new Response(
        false,
        'Record Not Found.'
    );

    $this->assertEquals($response, $this->object->create($request));
}

As you can see, there's a lot of duplication, so let's use dataprovider.

2 - Using @dataProvider

protected function getDataForTest()
{
    return array(
        array(self::$registrationRecord, true, 'successful'),
        array(null, false, 'Record Not Found.')
    );
}

/**
* @dataProvider getDataForTest
* @test
*/
public function ifTrue($getRecordValue, $bool, $message)
{
    $this->db->expects($this->once())
    ->method('getRecord')
    ->will($this->returnValue($getRecordValue);

    $request = $this->createRequest(array(
        'id' => '10',
        'code' => 'BB'
    ));

    $response = new Response(
        $bool,
        $message
    );

    $this->assertEquals($response, $this->object->create($request));
}

Using @dataProvider you can use as many values as you want to test all cases.

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

2 Comments

Hey thx for your answer `i have tried the first way but it then says: expect not found in class
Where and when do you instanciate your dbMock?
3

I think you should use the PHPUnit at() method to check method invocation at certain index. So you must substitute the expects value argument with the correct index's call.

So you can use the following code:

//Setting up mock of database repository class
$this->db = $this->getMockBuilder('DatabaseRepository')
    ->disableOriginalConstructor()
    ->getMock();

$this->db->expects($this->at(0)) // Mock the  first call
    ->method('getRecord')
    ->will($this->returnValue(self::$registrationRecord));

$this->db->expects($this->at(1)) // Mock the  second call
    ->method('getRecord')
    ->willReturn(null);

http://www.andrejfarkas.com/2012/07/phpunit-at-method-to-check-method-invocation-at-certain-index/

Hope this help

7 Comments

Hey thx for your replay. I actualy tried this solution propably should of mentioned but it did nto work i had this message: d> when invoked at sequence index 0. The expected invocation at index 0 was never reached.
The assertion said that in your test the method was never executed
@Koper can you post the entire test class?
my test method or the method i am trying to stub
@Koper, in order to replicate your problem, post all the code you can post that can be useful for local execute your scenario
|

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.