2016-10-25 5 views
2

question très simple:accesseurs Moose dans Catalyst ("ne peut pas utiliser la chaîne comme HASH ref" erreur)

package MyApp::Model::Foo; 
use Moose; 
use namespace::autoclean; 
extends 'Catalyst::Model'; 
has 'firstname' => (is => 'ro', isa => 'Str'); # to be populated in config file 

# ... 

sub check_name { 
    my $self = shift; 
    my $firstname = $self->firstname; 
    # ... 
} 

Quand j'appelle check_name() à partir d'un script de test, à la ligne "$ self-> prenom" J'obtiens l'erreur Can't use string ("MyApp::Model::Foo") as a HASH ref while "strict refs" in use at reader MyApp::Model::Foo::firstname. Comment suis-je censé l'utiliser?

Je ne peux pas reproduire le test car il est trop étendu, mais au moment où j'exécute le script de test, j'ai appelé un script d'installation qui charge l'application Catalyst (et donc lit le fichier de configuration Catalyst), déploie Le script de test a fonctionné correctement dans la version d'origine (qui n'a pas pris de valeur dans le fichier de configuration, c'est ce que j'essaie de faire maintenant, à l'origine j'ai transmis une valeur), et le bit correspondant est tout simplement

my $name_check = MyApp::Model::Foo->check_name(); 
ok(defined $name_check, "Name is OK"); 
+1

Veuillez inclure le script de test. Votre 'check_name' est correct. Quelque chose d'autre doit être faux. – simbabque

+1

Il semble que vous appeliez 'check_name()' comme méthode de classe plutôt que comme méthode d'objet. Mais sans voir l'appel à 'check_name()' nous ne pouvons pas être sûrs. S'il vous plaît [modifier votre question] (http://stackoverflow.com/posts/40243560/edit) pour ajouter le code qui appelle 'check_name()'. –

+1

Je pensais cela aussi, mais je pense aussi que cela pourrait être lié à ce qui se passe avec le fichier _config_ là. Parce que dans un script de test, il n'y aurait pas de plugin ConfigLoader @Dave. – simbabque

Répondre

3

Il semble que vous voulez faire une sorte d'unité-test, ou peut-être un test d'intégration, et vérifier si yo Notre application obtient les données correctes du fichier de configuration.

Les composants Catalyst (Models, Views et Controller) sont des objets Moose, vous avez raison. Pour qu'ils aient de la magie Moose (ce qui n'est pas vraiment magique), vous devez les instancier. Vous ne pouvez pas simplement appeler un accesseur en tant que méthode de classe.

use MyApp::Model::Foo; 
my $name_check = MyApp::Model::Foo->new->check_name(); 

Mais cela ne fonctionnerait pas, parce que maintenant vous avez une nouvelle instance de l'objet modèle, et il n'a pas le nom défini par la configuration. Catalyst se charge en interne de créer les objets pour vous, y compris leur configuration. Vous avez dit que vous avez un Catalyst en cours d'exécution. Vous pouvez utiliser Catalyst::Test pour y accéder, obtenir un objet de contexte $c, puis utiliser l'accesseur model pour obtenir le bon type d'objet de modèle ayant reçu la configuration.

La fonction ctx_request permet à Catalyst de gérer une requête et renvoie l'objet réel HTTP::Response ainsi que l'objet de contexte. Vous pouvez alors travailler avec ce contexte.

use Catalyst::Test 'MyApp'; 
use Test::More; 

my ($res, $c) = ctx_request('/'); 
ok defined $c->model('Foo')->name, 'Name is defined'; 

Vous avez probablement déjà Catalyst :: Test dans votre pile de test quelque part. Sinon, vous faites quelque chose de bizarre. Notez que cela ne fonctionne pas si vous voulez que la session soit attachée à un certain utilisateur, donc si vous avez un Test::WWW::Mechanize::Catalyst ou un autre agent utilisateur qui a un cookie de session, vous devrez extraire le cookie et créer le vôtre. HTTP::Request que d'utiliser le cookie jar des agents utilisateur pour placer le cookie dans cette requête avant de le transmettre au ctx_request. Notez également que le test que vous faites n'est pas très utile, sauf si vous construisez le code qui lit la configuration. Et même dans ce cas, vous pouvez créer des tests unitaires qui ne nécessitent pas un Catalyst complet.

+0

Il suffit de le réparer @Dave;) – simbabque

+1

Merci pour cette réponse extrêmement détaillée, ce qui m'a permis de voir ce qui se passait. La suite de tests était en fait déjà configurée comme vous le suggérez, avec ctx_request. Mais la plupart des tests n'ont pas été appelés par Catalyst, c'est-à-dire n'utilisant aucune magie Catalyst, donc juste donné le nom du module comme 'MyApp :: Model :: Foo'. Dans ce cas, j'avais besoin d'utiliser tous les internes de Cat, donc il suffisait de changer l'appel de 'mon $ name_check = $ c-> model ('Foo') -> check_name()' était tout ce dont j'avais besoin. – user1235777

+0

@ user1235777 Si vous voulez de vrais tests unitaires, alors créer vos propres objets est très bien. Pour les modèles et peut-être les vues qui ont du sens. Pour les contrôleurs, je pense qu'ils comptent beaucoup sur le contexte pour bien fonctionner sans réponses, sauf si vous avez beaucoup d'aides là-bas. Mais alors c'est une bonne raison de refactoriser de toute façon. La plupart du temps, j'ai des configurations de test spécifiques pour la suite de tests. L'utilisation d'un suffixe local et la définition de la variable ENV dans votre coureur de test est plutôt soignée. C'est aussi pourquoi je ne recommanderais pas un test juste pour vérifier si une valeur a été définie par Catalyst. Ça va bien se casser si ce n'était pas le cas. :) – simbabque