2016-10-25 9 views
2

Очень простой вопрос:Муз аксессоров в Catalyst («Невозможно использовать строку как HASH исх» ошибка)

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; 
    # ... 
} 

Когда я звоню check_name() из тестового сценария, в строке «$ self-> Firstname» Я получаю ошибку Can't use string ("MyApp::Model::Foo") as a HASH ref while "strict refs" in use at reader MyApp::Model::Foo::firstname. Как я должен использовать это?

Я не могу воспроизвести тестовый материал, поскольку он слишком обширен, но к тому моменту, когда я запускаю тестовый сценарий, я вызвал сценарий установки, который загружает приложение Catalyst (и, таким образом, считывает конфигурационный файл Catalyst), развертывает и заполняет таблицы базы данных и т. д.

Тест-скрипт отлично работал в исходной версии (что не принимало значения из файла конфигурации, вот что я пытаюсь сделать сейчас, изначально я передал значение) и соответствующий бит просто

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

Пожалуйста, включите тестовый скрипт. Ваше 'check_name' правильно. Что-то еще должно быть неправильно. – simbabque

+1

Похоже, вы могли бы вызывать 'check_name()' как метод класса, а не метод объекта. Но, не увидев вызов 'check_name()', мы не можем быть уверены. Пожалуйста, отредактируйте свой вопрос] (http://stackoverflow.com/posts/40243560/edit), чтобы добавить код, который вызывает 'check_name()'. –

+1

Я тоже думал об этом, но я также думаю, что это может быть связано с тем, что происходит с файлом _config. Потому что в тестовом скрипте не будет плагина ConfigLoader @Dave. – simbabque

ответ

3

Похоже, вы хотите сделать вид-единицы-теста, или, может быть интеграционного теста, и если йо проверить Ур получает правильные данные из файла конфигурации.

Компоненты Catalyst (модели, виды и контроллер) являются объектами Moose, у вас все в порядке. Для того, чтобы у них была магия Лося (которая на самом деле не волшебна), вам нужно создать их. Вы не можете просто вызвать аксессор в качестве метода класса.

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

Но это не будет работать, потому что теперь у вас есть нового экземпляра модель объекта, и он не имеет имени, настроенное через конфиг.

Catalyst внутренне заботится о создании объектов для вас, включая их конфигурацию. Вы сказали, что у вас работает Catalyst. Вы можете использовать Catalyst::Test, чтобы перейти туда, получить объект контекста $c, а затем использовать аксессуар model, чтобы получить нужный тип объекта модели, которому была предоставлена ​​конфигурация.

Функция ctx_request позволяет Catalyst обрабатывать запрос и возвращает фактический объект HTTP::Response, а также объект контекста. Затем вы можете работать с этим контекстом.

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

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

Возможно, у вас уже есть Catalyst :: Испытайте где-нибудь тестовую стек. Если нет, вы делаете что-то странное.

Обратите внимание, что это не работает, если вы хотите, чтобы сеанс был прикреплен к определенному пользователю, поэтому, если у вас есть Test::WWW::Mechanize::Catalyst или другой пользовательский агент, у которого есть куки-файл сеанса, вам нужно будет извлечь файл cookie и создать собственный HTTP::Request, чем использовать пользовательские агенты cookie jar, чтобы поместить cookie в этот запрос, прежде чем передать его на ctx_request.

Также обратите внимание, что тест, который вы выполняете, не очень полезен, если только вы не создаете код, который выполняет чтение конфигурации. И даже тогда вы можете построить модульные тесты, которые не требуют полного запуска Catalyst.

+0

Просто исправьте это @Dave;) – simbabque

+1

Спасибо за этот чрезвычайно подробный ответ, который позволил мне увидеть, что происходит. Набор тестов был фактически настроен, как вы предлагаете, с помощью ctx_request. Но большинство тестов не вызывалось через Catalyst, т. Е. Не использовало никакой магии Catalyst, поэтому просто присвоило имя модуля как «MyApp :: Model :: Foo». В этом случае мне нужно было использовать все внутренние элементы Cat, поэтому просто изменить вызов модели 'my $ name_check = $ c-> ('Foo') -> check_name()' было всем, что мне нужно. – user1235777

+0

@ user1235777 Если вы хотите настоящие модульные тесты, тогда создание ваших собственных объектов в порядке. Для моделей и, возможно, Views, что имеет смысл. Для контроллеров я чувствую, что они сильно полагаются на Контекст, чтобы хорошо работать без ответов, если у вас там много помощников. Но тогда это хорошая причина для реорганизации. В большинстве случаев у меня есть специальные тестовые конфигурации для набора тестов. Использование локального суффикса и установка переменной ENV для него в тестовом бегуне довольно аккуратно. Вот почему я бы не рекомендовал тест, чтобы проверить, установлено ли значение Catalyst. Это сломается, если не получится. :) – simbabque