Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Codeigniter Unit-testing models

I'm new to unit-testing, so this is maybe a little dumb question. Imagine, we have a simple model method.

public function get_all_users($uid = false, $params = array()){
    $users = array();
    if(empty($uid) && empty($params)){return $users;}
    $this->db->from('users u');
    if($uid){
        $this->db->where('u.id',(int)$id);
    }
    if(!empty($params)){
       if(isset($params['is_active']){
          $this->db->where('u.status ', 'active');
       }
       if(isset($params['something_else']){ // some more filter actions}
    }
    $q = $this->db->get();
    if($q->num_rows()){
        foreach($q->result_array() as $user){
            $users[$user['id']] = $user;
        }
    }
    $q->free_result();
    return $users;
}

The question is how a _good test would be written for it? UPD: I guess, the best unit-testing library for CI is Toast, so example i'm looking for, preferable be written using it. Thanks.

like image 506
DCrystal Avatar asked Feb 16 '10 14:02

DCrystal


1 Answers

I'm using toast too, and mostly I use it to test a model methods. To do it, first truncate all table values, insert a predefined value, then get it. This is the example of test I used in my application:

class Jobads_tests extends Toast
{
  function Jobads_tests()
  {
    parent::Toast(__FILE__);
    // Load any models, libraries etc. you need here
    $this->load->model('jobads_draft_model');
    $this->load->model('jobads_model');
  }

  /**
   * OPTIONAL; Anything in this function will be run before each test
   * Good for doing cleanup: resetting sessions, renewing objects, etc.
   */
  function _pre()
  {
    $this->adodb->Execute("TRUNCATE TABLE `jobads_draft`");
  }

  /**
   * OPTIONAL; Anything in this function will be run after each test
   * I use it for setting $this->message = $this->My_model->getError();
   */
  function _post()
  {
    $this->message = $this->jobads_draft_model->display_errors(' ', '<br/>');
    $this->message .= $this->jobads_model->display_errors(' ', '<br/>');
  }

  /* TESTS BELOW */
  function test_insert_to_draft()
  {
    //default data
    $user_id = 1;

    //test insert
    $data = array(
      'user_id' => $user_id,
      'country' => 'ID',
      'contract_start_date' => strtotime("+1 day"),
      'contract_end_date' => strtotime("+1 week"),
      'last_update' => time()
    );
    $jobads_draft_id = $this->jobads_draft_model->insert_data($data);
    $this->_assert_equals($jobads_draft_id, 1);

    //test update
    $data = array(
      'jobs_detail' => 'jobs_detail',
      'last_update' => time()
    );
    $update_result = $this->jobads_draft_model->update_data($jobads_draft_id, $data);
    $this->_assert_true($update_result);

    //test insert_from_draft
    $payment_data = array(
      'activation_date' => date('Y-m-d', strtotime("+1 day")),
      'duration_amount' => '3',
      'duration_unit' => 'weeks',
      'payment_status' => 'paid',
      'total_charge' => 123.45
    );
    $insert_result = $this->jobads_model->insert_from_draft($jobads_draft_id, $payment_data);
    $this->_assert_true($insert_result);

    //draft now must be empty
    $this->_assert_false($this->jobads_draft_model->get_current_jobads_draft($user_id));

  }
}

I'm using AdoDB in my application, but don't get confuse with that. You can do $this->db inside the test controller, after you load the database library. You can put it in autoload so it will automatically loaded.

See that in my code, before the test is run, the table is truncated. After run, I will get any error that might occured. I do assert for a predefined insert and update. Using Toast to test the model will make you sure that the model's method doing exactly the task that you want it to do. Make the test that you need, and make sure you cover all the possibilities of input and output values.

like image 140
Donny Kurnia Avatar answered Sep 18 '22 04:09

Donny Kurnia