sexta-feira, 19 de março de 2010

Erro no teste de validação "not null" em campo string no CakePHP

No início das minhas experiências utilizando BDD com o cakephp e a sua biblioteca de testes (CakeTest estendendo SimpleTest), tive um problema que considero no mínimo bizarro.
Vou tentar demonstrar o problema que eu tive e como eu resolvi:
Pra começar irei criar uma tabela simples com apenas um campo id (int) e um campo nome (string):
CREATE TABLE  `teste`.`usuarios` (
`id` INT NOT NULL AUTO_INCREMENT ,
`nome` VARCHAR( 255 ) NOT NULL ,
PRIMARY KEY ( `id` )
)


Agora irei gerar pelo bake o modelo dessa tabela com a validação "notEmpty" (recomendada pelo bake para um campo de string) e também os arquivos de teste:

Possible Models based on your current database:
1. Usuario
Enter a number from the list above, type in the name of another model, or 'q' to exit
[q] > 1
Would you like to supply validation criteria for the fields in your model? (y/n)
[y] > y

[...]

Field: nome
Type: string
---------------------------------------------------------------
Please select one of the following validation options:
---------------------------------------------------------------
[...]
20 - notEmpty
29 - Do not do any validation on this field.
... or enter in a valid regex validation string.

[20] >
Would you like to define model associations (hasMany, hasOne, belongsTo, etc.)? (y/n)
[y] > n

---------------------------------------------------------------
The following Model will be created:
---------------------------------------------------------------
Name: Usuario
Validation: Array
(
[nome] => notempty
)


Baking model class for Usuario...

Creating file /home/duke/www/cakephp/app/models/usuario.php
Wrote /home/duke/www/cakephp/app/models/usuario.php

[...]
Baking test fixture for Usuario...
Creating file /home/duke/www/cakephp/app/tests/fixtures/usuario_fixture.php
Wrote /home/duke/www/cakephp/app/tests/fixtures/usuario_fixture.php

Baking unit test for Usuario...

Creating file /home/duke/www/cakephp/app/tests/cases/models/usuario.test.php
Wrote /home/duke/www/cakephp/app/tests/cases/models/usuario.test.php



Agora abrirei o arquivo de testes do modelo (usuario.test.php) e criarei o seguinte método de teste:

function testAttributes() {
$this->assertFalse($this->Usuario->validates(), 'should be invalid');
$this->Usuario->set("nome", "adriano");
$this->assertTrue($this->Usuario->save(), 'should be valid');
}

Estou fazendo 2 asserts, ou seja, estou garantindo duas coisas:
1. que ao tentar validar um objeto "Usuario" sem ter atribuído nenhum parâmetro, ele será inválido pois o campo "nome" é obrigatório;
2. e que após definir o campo "nome" para "adriano" e tentar salvar, deve ser válido.

Porém ao rodar os testes terei o seguinte resultado:
FAILED
should be invalid at [.../app/tests/cases/models/usuario.test.php line 14]
PASSED [...]
should be valid at [.../app/tests/cases/models/usuario.test.php line 16]

Ou seja, ele falhou no primeiro teste, logo, ele trata o objeto usuário "cru" como um objeto válido.
O meu teste está correto, eu quero que aconteça exatamente como designei nas minhas assertions, porém parece que o cake não entende "notEmpty" da mesma forma que eu.
Para esse teste passar, teria que setar o nome do usuário vazio antes da assertion:
$this->Usuario->set("nome", "");

Ai sim ele falharia o validate e o teste passaria, porém eu quero considerar que se a posição do array de dados do objeto ($this->Usuario->data["nome"]) não existir, é porque ela está vazia.
Para obter esse resultado, eu altero a regra de validação no modelo:
O bake deve gera a validação apenas criando a regra de notempty para o campo:

var $validate = array(
'nome' => array('notempty')
);

e eu alterarei para o campo aceitar todos os caracteres visíveis e ser obrigatório:

var $validate = array(
'rule' => array('custom', '/^[\x20-\x7E]+$/i'),
'required' => true
);

agora se rodar os testes novamente, eles irão passar, mesmo sem declarar como vazio o nome do usuário

Nenhum comentário: