3

I'm currently trying to write a unit test for the following model:

<?php
namespace App\Model\Table;

use App\Model\Entity\User;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

/**
 * Users Model
 *
 * @property \Cake\ORM\Association\HasMany $Comments
 * @property \Cake\ORM\Association\BelongsToMany $Albums
 */
 class UsersTable extends Table
 {

    /**
     * Initialize method
     *
     * @param array $config The configuration for the Table.
     * @return void
     */
     public function initialize(array $config)
     {
       parent::initialize($config);

       $this->table('users');
       $this->displayField('id');
       $this->primaryKey('id');

       $this->addBehavior('Timestamp');

       $this->hasMany('Comments', [
           'foreignKey' => 'user_id'
       ]);
       $this->belongsToMany('Albums', [
          'foreignKey' => 'user_id',
          'targetForeignKey' => 'album_id',
          'joinTable' => 'users_albums'
       ]);
      }

/**
 * @Author: Mark van der Laan
 * @Date: 23-02-2016
 * @Description: Validating rules for the user model. Some additional, more complex validation rules are added.
 * @param \Cake\Validation\Validator $validator Validator instance.
 * @return \Cake\Validation\Validator
 */
public function validationDefault(Validator $validator)
{
    // id
    $validator
        ->integer('id')
        ->allowEmpty('id', 'create');

    // username
    $validator
        ->requirePresence('username', 'create')
        ->notEmpty('username')
        // Enabled, just in case that the username will be an email address
        ->email('username')
        ->add('username', [
            'length' => [
                'rule' => ['minLength', 7],
                'message' => 'Username needs to be at least 7 characters long!',
            ]
        ]);

    // password
    $validator
        ->requirePresence('password', 'create')
        ->notEmpty('password')
        ->add('password', [
            'length' => [
                'rule' => ['minLength', 7],
                'message' => 'Password needs to be at least 7 characters long!',
            ]
        ]);

    // sign_in_count
    $validator
        ->integer('sign_in_count')
        ->requirePresence('sign_in_count', 'create')
        ->notEmpty('sign_in_count');

    // ip address
    $validator
        ->allowEmpty('current_sign_in_ip')
        ->requirePresence('current_sign_in_ip', 'create')
        // Currently checking for both IPv4 and IPv6 addresses
        ->ip('current_sign_in_ip', 'both');

    // active
    $validator
        ->boolean('active')
        ->requirePresence('active', 'create')
        ->allowEmpty('active');

    return $validator;
}

/**
 * Returns a rules checker object that will be used for validating
 * application integrity.
 *
 * @param \Cake\ORM\RulesChecker $rules The rules object to be modified.
 * @return \Cake\ORM\RulesChecker
 */
public function buildRules(RulesChecker $rules)
{
    $rules->add($rules->isUnique(['username']));
    return $rules;
}
}

It is important for me to test the validationDefault method which I try to do with the following code snippet:

public function testValidationDefault()
{
    $data = ['username' => 'adminadmin@mixtureweb.nl',
             'password' => 'testtest123',
             'sign_in_count' => 0,
             'current_sign_in_ip' => '127.0.0.1',
             'active' => 'true'
            ];
    $this->assertTrue($this->Users->save($data));
    // $this->assertTrue($data);
}

As I try to do this, this will throw an error saying that I shouldn't pass an array to assertTrue method. Therefore, I'm trying to find examples but I couldn't find anything. Has anyone some references where I can find how to unit test validation rules? (so far I couldn't find anything in the documentation)

Update

public function testValidationDefault()
{
    $data = ['username' => 'adminadmin@mixtureweb.nl',
             'password' => 'testtest123',
             'sign_in_count' => 0,
             'current_sign_in_ip' => '127.0.0.1',
             'active' => true
            ];
    $user = $this->Users->newEntity($data);
    $saved = $this->Users->save($user);
    $this->assertTrue($saved);
    // $this->assertTrue($data);
}

This will give 'Failed asserting that App\Model\Entity\User Object &0000000011b3c53b0000000040aca14b is true'. Does anyone know what I'm doing wrong?

dav
  • 8,931
  • 15
  • 76
  • 140
markvdlaan93
  • 613
  • 10
  • 26

1 Answers1

8

Take a look at what Table::save() returns, it's \Cake\Datasource\EntityInterface|bool. On success it returns the persisted entity, on failure it returns boolean false. So your save operation succeeds and it will return an entity, hence the error.

If you want to test validation, you should either use the validator object that your table class offers (Table::validationDefault() via Table::validator()), or use Table::patchEntity() or Table::newEntity() and test the value of Entity:errors().

Patching/creating entities is where validation in the model layer happens, the saving process will only apply application rules.

public function testValidationDefault()
{
    $data = [
        'username' => 'adminadmin@mixtureweb.nl',
        'password' => 'testtest123',
        'sign_in_count' => 0,
        'current_sign_in_ip' => '127.0.0.1',
        'active' => true
    ];
    $user = $this->Users->newEntity($data);
    $this->assertEmpty($user->errors()); // empty = no validation errors
}

See also

ndm
  • 59,784
  • 9
  • 71
  • 110