Welcome Guest, Not a member yet? Register   Sign In
Unit Testing & Mock Objects
#15

[eluser]ch5i[/eluser]
Hello,

after a lot of trial & error I got this finally to work.
Thanks for your post Aniket, that got me started.

So, here it is: A simple example on how to mock the CI database class.


User model (test subject)
Code:
<?php

/**
* User_model
*/
class User_model extends Model {

    function User_model()
    {
        parent::__construct();
    }


    public function getAllUsers()
    {    
        return $this->db->get('users');
    }


    public function add($firstname)
    {    
        $usr = new stdClass();
        $usr->firstname = $firstname;
        return $this->db->insert('users', $usr);
    }

}


Unit Test Case
Code:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');


class TestMockClass extends UnitTestCase{
    
    // holds reference to ci instance
    private    $_ci = NULL;
    
    
    public function __construct()
    {
        $this->UnitTestCase("Mock object demo 2");
        
        // fetch ref to ci instance
        $this->_ci =& get_instance();
        
        // generate a class that has the same interface as
        // CI's currently loaded db
        Mock::generate(get_class($this->_ci->db), 'fake_DB');
        
        // generate a class with the same interface as CI_DB_result
        require_once(BASEPATH.'database/DB_result'.EXT);
        Mock::generate('CI_DB_result', 'fake_DB_result');
        
        // load the test subject (user model)
        $this->_ci->load->model('user_model');
    }
    
    
    public function setUp()
    {
        // replace CI's db with the faked one
        $this->_ci->db = new fake_DB();
        
        // THIS MAKES IT WORK
        // explicitly replace the db object
        // in the scope of the test subject
        // to get the references working...
        $this->_ci->user_model->db = $this->_ci->db;
    }
    
    
    public function tearDown()
    {    
        // not needed
        // unset($this->_ci->db);
    }
    
    
    public function testAddNewUser()
    {    
        // the 'add' method in user_model calls
        // the 'insert' method of CI's db object ($this->db->insert()),
        // which we replaced with the fake (mocked) one.
        // It has the same interface, but no implementation for the methods
        // so we have to tell it what to return for a given method call
        //
        // array('users', '*') means first param of insert must
        // be 'users' (the tablename), the second can be whatever
        $this->_ci->db->setReturnValue(
                                        'insert',
                                        TRUE,
                                        array('users', '*')
                                       );

        $this->assertTrue($this->_ci->user_model->add('Jack'), '%s');
    }
        
    
    public function testGetDbResult()
    {
        // create some dummy data to return later
        $jim = new stdClass();
        $jim->firstname = 'Jim';
        $jim->id        = 1;
    
        $joe = new stdClass();
        $joe->firstname = 'Joe';
        $joe->id        = 4;
        
        $result = array($jim, $joe);
                
        // set the query to mock ci_db_result
        // we want to get a mock db_result
        // where we can control what comes out of our
        // 'virtual' database
        $query = new fake_DB_result();

        // set the return value for the num_rows() method
        $query->setReturnValue('num_rows', 2);
        
        // set the return value for the row(2) method call
        $query->setReturnReference('row', $joe, array(2));
        
        // set the return value for the result() method call
        $query->setReturnReference('result', $result);
        
        // set the return value for db->get('users') method call
        $this->_ci->db->setReturnReference(
                                            'get',
                                            $query,
                                            array('users')
                                           );

        // implicitly call the db->get() method (in user_model)
        $returned_query = $this->_ci->user_model->getAllUsers();
        $this->assertReference($query, $returned_query);
        
        // call num_rows() on the returned (fake) db_result
        $this->assertEqual($returned_query->num_rows(), 2);
        
        // call row(2) on the returned (fake) db_result
        $this->assertEqual($returned_query->row(2)->firstname, 'Joe');
        
        // call result() method on the returned (fake) db_result
        foreach($returned_query->result() as $user) {
            $this->assertPattern('#J.{2}#', $user->firstname);
        }
        
    }
}

Sidenote:
I use SimpleTest, set up as described in the Wiki.
Well, almost as described, I do not autoload the simpletester library (step 5), but have a unit test controller which loads it and calls the Run() method, so that the tests are not run everytime i call a controller.


Messages In This Thread
Unit Testing & Mock Objects - by El Forum - 02-23-2009, 11:10 PM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 03:56 AM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 05:34 AM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 06:22 AM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 06:25 AM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 06:37 AM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 06:50 AM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 06:55 AM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 06:56 AM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 06:57 AM
Unit Testing & Mock Objects - by El Forum - 02-24-2009, 07:06 AM
Unit Testing & Mock Objects - by El Forum - 02-27-2009, 05:27 AM
Unit Testing & Mock Objects - by El Forum - 04-23-2009, 10:48 PM
Unit Testing & Mock Objects - by El Forum - 04-24-2009, 03:14 PM
Unit Testing & Mock Objects - by El Forum - 06-16-2009, 04:44 PM
Unit Testing & Mock Objects - by El Forum - 06-05-2013, 08:31 AM



Theme © iAndrew 2016 - Forum software by © MyBB