1

I'm new to CakePHP and PHPUnit and I want to test one of my controllers. So far I have this method I like to test:

public function getAlternatives($id = null){
    // ID parameter given or is NaN?
    if (!$id || !is_numeric($id)) {
        throw new BadRequestException();
    }

    // Error if object not found
    if (!$this->Designitem->exists($id)) {
        throw new NotFoundException();
    }

    $alternatives = $this->Designitem->getItemsWithFunritures($id);

    $this->set(array(
        'alternatives' => $alternatives,
        '_serialize' => array('alternatives'),
        '_jsonp' => true));
}

Now I want to test whether the getItemsWithFurnitures is called on my model Designitem. To test this I implemented this test:

public function testGetAlternativesWithValidID() {
    $id = 1;
    $url = array('controller' => 'Designitems', 'action' => 'getAlternatives', $id . '.json');

    $expected = array(
        'Designitem' =>
            array(
                'id' => 1,
                'design_id' => 1,
                'furniture_id' => 1,
                'template_id' => 1,
            ),
    );

    $designitems = $this->generate('Designitems', array(
        'methods' => array(
            'getAlternatives',
        ),
        'models' => array(
            'Designitem' => array('getItemsWithFunritures'),
        ),
    ));
    $designitems->Designitem
        ->expects($this->once())
        ->method('getItemsWithFunritures')
        ->will($this->returnValue($expected));

    $result = $this->testAction($url);

    $this->assertEquals(json_encode($expected), $result);
}

EDIT: My Designitems Fixture contains one stubbed entry. It looks like this:

class DesignitemFixture extends CakeTestFixture {

public $fields = array(
    'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'unsigned' => false, 'key' => 'primary'),
    'design_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'unsigned' => false),
    'furniture_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'unsigned' => false),
    'template_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'unsigned' => false),
    'templateitem_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'unsigned' => false),
    'amount' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 5, 'unsigned' => false),
    'feedback' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => 20, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'),
    'clicks' => array('type' => 'integer', 'null' => true, 'default' => '0', 'unsigned' => false),
    'ilike' => array('type' => 'boolean', 'null' => false, 'default' => null),
    'dislike' => array('type' => 'boolean', 'null' => false, 'default' => null),
    'dislike_reason' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 100, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'),
    'dislike_comment' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 2000, 'collate' => 'utf8_general_ci', 'charset' => 'utf8'),
    'parent_id' => array('type' => 'integer', 'null' => true, 'default' => null, 'unsigned' => false),
    'has_alternatives' => array('type' => 'boolean', 'null' => true, 'default' => null),
    'is_selected' => array('type' => 'boolean', 'null' => true, 'default' => null),
    'is_recommendation' => array('type' => 'boolean', 'null' => true, 'default' => null),
    'deleted' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => 4, 'unsigned' => false),
    'deleted_date' => array('type' => 'datetime', 'null' => true, 'default' => null),
    'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
    'modified' => array('type' => 'datetime', 'null' => true, 'default' => null),
    'indexes' => array(
        'PRIMARY' => array('column' => 'id', 'unique' => 1)
    ),
    'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'InnoDB')
);

public $records = array(
    array(
        'id' => 1,
        'design_id' => 1,
        'furniture_id' => 1,
        'template_id' => 1,
        'templateitem_id' => 1,
        'amount' => 1,
        'feedback' => 'Lorem ipsum dolor ',
        'clicks' => 1,
        'ilike' => 1,
        'dislike' => 1,
        'dislike_reason' => 'Lorem ipsum dolor sit amet',
        'dislike_comment' => 'Lorem ipsum dolor sit amet',
        'parent_id' => 1,
        'has_alternatives' => 1,
        'is_selected' => 1,
        'is_recommendation' => 1,
        'deleted' => 0,
        'deleted_date' => '2016-07-14 12:05:39',
        'created' => '2016-07-14 12:05:39',
        'modified' => '2016-07-14 12:05:39'
    ),
);

}

When I run the test, I get an error that the getItemsWithFurnitures returned null:

Test result

Can anyone tell me what I'm doing wrong? Thank you!

1 Answer 1

1

I found a solution to the problem. My problem was that not the getItemsWithFurnitures returned null but the tested method getAlternatives isn't returning any value (-> null). So I have to check if the set value $this->set(...); is the same as the expected array. To achieve this I have to change the return method of the testAction(...) by passing array('return' => 'contents'). It will then return the produced content instead of the methods return value. The working test looks like this:

public function testGetAlternativesWithValidID() {
    $id = 1;
    $url = array('controller' => 'Designitems', 'action' => 'getAlternatives', $id . '.json');

    $this->_generateMockWithAuthUserId('Designitems', 1);

    $expected = array(
        'Designitem' =>
            array(
                'id' => 1,
                'design_id' => 1,
                'furniture_id' => 1,
                'template_id' => 1,
            ),
    );

    $data = $this->getMockForModel('Designitem', array('getItemsWithFunritures'));
    $data->expects($this->once())
        ->method('getItemsWithFunritures')
        ->will($this->returnValue($expected));

    $result = $this->testAction($url, array('return' => 'contents'));

    // Delete all whitespaces from the result.
    $result = preg_replace('/\s+/', '', $result);
    // Add the surrounding alternatives array to the expected and convert to json-format.
    $expected = json_encode(array('alternatives' => $expected));

    $this->assertEquals($expected, $result);
}

Because I add these items into another array 'alternatives' while setting it to the view, I have to place the expected array in this 'alternatives'-array. I also had to replace all whitespaces because the json encoding methods used are different. In order to compare them they have to be exactly the same so I removed the whitespaces and the test passes.

I hope someone can use this info.

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

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.