包装测试::Mojo;使用Mojo::Base-Base;#“艾米:他知道你什么时候睡觉。#教授:他知道你什么时候在听。#利拉:他会追捕你,然后把你从这里轰到巴基斯坦。#佐伊德伯格:哦。#赫尔墨斯:你最好不要呼吸,你最好不要动。#本德:我告诉你,你最好死了,伙计。#弗莱:圣诞老人要枪杀你了!"使用Mojo::IOLoop;使用Mojo::JSON qw(j);使用Mojo::JSON::指针;使用Mojo::Server;使用Mojo::UserAgent;使用Mojo::Util qw(解码-编码);使用测试::更多();具有handler=>sub{\&handler};具有[qw(消息成功tx)];具有ua=>sub{Mojo::UserAgent->new(unsecure=>1)->ioloop(Mojo::ioloop->singleton)};#无声或大声测试$ENV{MOJO_LOG_LEVEL}||=$ENV}HARNESS_IS_VERBOSE}?'trace':'致命';子应用程序{my($self,$app)=@_;返回$self->ua->server->app,除非$app;$self->ua->server->app($app);return$self;}子属性is{my($self,$selector,$attr,$value,$desc)=@_;$desc=_desc($desc,qq{选择器“$selector”}处属性“$attr”的精确匹配);返回$self->test('is',$self->_attr($selector,$attr),$value,$desc);}子属性_isnt{my($self,$selector,$attr,$value,$desc)=@_;$desc=_desc($desc,qq{选择器“$selector”}处属性“$attr”不匹配);返回$self->test('isnt’,$self->_attr($selector,$attr),$value,$desc);}子类属性{my($self、$selector、$attr、$regex、$desc)=@_;$desc=_desc($desc,qq{选择器“$selector”}处属性“$attr”的类似匹配);返回$self->test('like',$self->_attr($selector,$attr),$regex,$desc);}子属性不同{my($self、$selector、$attr、$regex、$desc)=@_;$desc=_desc($desc,qq{选择器“$selector”}的属性“$attr”没有类似匹配项);返回$self->test(“不一样”,$self->_attr($selector,$attr),$regex,$desc);}子内容_is{my($self,$value,$desc)=@_;返回$self->test('is',$self->tx->res->text,$value,_desc($desc,'内容精确匹配');}子内容_isnt{my($self,$value,$desc)=@_;return$self->test('isnt',$self->tx->res->text,$value,_desc($desc,'内容不匹配');}子内容类{my($self,$regex,$desc)=@_;return$self->test('like',$self->tx->res->text,$regex,_desc($desc,'内容相似');}子内容类型{my($self,$type,$desc)=@_;返回$self->test('is',$self->tx->res->headers->content_type,$type,_desc($desc,“content-type:$type”);}子内容类型{my($self,$type,$desc)=@_;返回$self->test('isnt’,$self->tx->res->headers->content_type,$type,_desc($desc,“not content-type:$type”);}子内容类型类{my($self,$regex,$desc)=@_;return$self->test('like',$self->tx->res->headers->content_type,$regex,_desc($desc,'内容类型类似'));}子内容类型unlike{my($self,$regex,$desc)=@_;$desc=_desc($desc,'内容类型不相似');返回$self->test(“不一样”,$self->tx->res->headers->content_type,$regex,$desc);}子内容不同{my($self,$regex,$desc)=@_;return$self->test(“不一样”,$self->tx->res->text,$regex,_desc($desc,“内容不相似”);}sub delete_ok{shift->_build_ok(删除=>@_)}子元素count_is{my($self,$selector,$count,$desc)=@_;my$size=$self->tx->res->dom->find($selector)->size;返回$self->test('is',$size,$count,_desc($desc,qq{选择器“$selector”}的元素计数);}子元素_exists{my($self,$selector,$desc)=@_;$desc=_desc($desc,qq{选择器“$selector”的元素存在});返回$self->test('ok',$self->tx->res->dom->at($selector),$desc);}子元素_exists_not{my($self,$selector,$desc)=@_;返回$self->test('ok',!$self->tx->res->dom->at($selector),_desc($desc,qq{没有选择器“$selecter”}的元素);}子饰面_ok{my$self=班次;如果$self->tx->is_websocket,则$self->tx->finish(@_);Mojo::IOLoop->one_tick while$self->{finished};return$self->test('ok',1,'closed WebSocket');}完工合格{my($self,$code)=@_;Mojo::IOLoop->one_tick while$self->{finished};Test::More::diag“WebSocket已关闭,状态为$self->{finished}[0]”,除非我的$ok=$self->{finished}[0]=$code;return$self->test('ok',$ok,“WebSocket关闭状态$code”);}子get_ok{shift->_build_ok(get=>@_)}子标题_ok{shift->_build_ok(head=>@_)}子标题_exists{my($self,$name,$desc)=@_;返回$self->test('ok',!!@{$self->tx->res->headers->every_header($name)},_desc($desc,qq{header“$name”exists});}子标题_exists_not{my($self,$name,$desc)=@_;返回$self->test('ok',!@{$self->tx->res->headers->every_header($name)},_desc($desc,qq{no“$name”header});}子标题_is{my($self,$name,$value,$desc)=@_;返回$self->test('is',$self->tx->res->headers->header($name),$value,_desc($desc,“$name:”.($value//''));}子标题_isnt{my($self,$name,$value,$desc)=@_;$desc=_desc($desc,“不是$name:”.($value//''));返回$self->test('isnt’,$self->tx->res->headers->header($name),$value,$desc);}类子标题{my($self,$name,$regex,$desc)=@_;$desc=_desc($desc,“$name类似”);返回$self->test('like',$self->tx->res->headers->header($name),$regex,$desc);}子标题不同{my($self,$name,$regex,$desc)=@_;返回$self->test('different',$self->tx->res->headers->header($name),$regex,_desc($desc,“$name不相似”);}sub-json_has{my($self,$p,$desc)=@_;$desc=_desc($desc,qq{具有JSON指针“$p”}的值);return$self->test('ok',!!Mojo::JSON::指针->new($self->tx->res->JSON)->contains($p),$desc);}sub-json_hasnt{my($self,$p,$desc)=@_;$desc=_desc($desc,qq{没有JSON指针“$p”}的值);return$self->test('ok',!Mojo::JSON::指针->new($self->tx->res->JSON)->contains($p),$desc);}子json_is{我的$self=轮班;my($p,$data)=@_>1?(移位,移位):('',移位);my$desc=_desc(移位,qq{精确匹配JSON指针“$p”});返回$self->test('is_departh',$self->tx->res->json($p),$data,$desc);}sub类json{my($self,$p,$regex,$desc)=@_;return$self->test('like',$self->tx->res->json($p),$regex,_desc($desc,qq{json指针“$p”}的类似匹配);}子json消息具有{my($self,$p,$desc)=@_;return$self->test('ok',$self->_json(contains=>$p),_desc($desc,qq{具有json指针“$p”}的值);}sub json消息hasnt{my($self,$p,$desc)=@_;return$self->test('ok',!$self->_json(contains=>$p),_desc($desc,qq{没有json指针“$p”}的值);}子json消息{my$self=班次;my($p,$data)=@_>1?(移位,移位):('',移位);return$self->test('is_depth',$self->_json(get=>$p),$data,_desc(shift,qq{json指针“$p”}的精确匹配);}子json消息类{my($self,$p,$regex,$desc)=@_;return$self->test('like',$self->_json(get=>$p),$regex,_desc($desc,qq{类似于json指针“$p”}));}子json消息不同{my($self,$p,$regex,$desc)=@_;$desc=_desc($desc,qq{JSON指针“$p”}没有类似匹配项);返回$self->test(“不一样”,$self->json(get=>$p),$regex,$desc);}sub json不一样{my($self、$p、$regex、$desc)=@_;$desc=_desc($desc,qq{JSON指针“$p”}没有类似匹配项);返回$self->test(“不一样”,$self->tx->res->json($p),$regex,$desc);}子消息_is{my($self,$value,$desc)=@_;返回$self->_message('is',$value,_desc($desc,'消息的精确匹配');}子消息_isnt{my($self,$value,$desc)=@_;return$self->_message('isnt’,$value,_desc($desc,'no match for message'));}子消息类{my($self,$regex,$desc)=@_;return$self->_message('like',$regex,_desc($desc,'message is similable'));}子消息ok{my($self,$desc)=@_;返回$self->test('ok',!!$self->_wait,_desc($desc,'message received'));}子消息不同{my($self,$regex,$desc)=@_;return$self->_message(“不一样”,$regex,_desc($desc,“消息不相似”));}sub新{my$self=shift->SUPER::new;返回$self,除非我的$app=shift;我的@cfg=@_?{config=>{config_override=>1,%{shift()}}}:();return$self->app(Mojo::Server->new->build_app($app,@cfg)),除非ref$app;return$self->应用程序($app->isa(“Mojolicious”)@cfg$app->config($cfg[0]{config}):$app:Mojo::Server->new->load_app($app,@cfg));}子选项_ok{shift->_build_ok(选项=>@_)}sub或{my($self,$cb)=@_;$self->$cb,除非$self->成功;return$self;}sub patch_ok{shift->_build_ok(补丁=>@_)}子post_ok{shift->_build_ok(post=>@_)}子输入ok{shift->_build_ok(put=>@_)}子请求ok{shift->_request_ok($_[0],$_[0]->req->url->to_string)}子重置会话{我的$self=轮班;$self->ua->cookie_jar->empty;返回$self->tx(undef);}子发送(_O){my($self,$msg,$desc)=@_;$desc=_desc($desc,'发送消息');除非$self->tx->is_websocket,否则返回$self->测试('ok',0,$desc);$self->tx->send($msg=>sub{Mojo::IOLoop->stop});Mojo::IOLoop->启动;返回$self->测试('ok',1,$desc);}子状态_is{my($self,$status,$desc)=@_;$desc=_desc($desc,“$status”。$self->tx->res->default_message($status));返回$self->test('is',$self->tx->res->code,$status,$desc);}子状态_isnt{my($self,$status,$desc)=@_;$desc=_desc($desc,“非$status”.$self->tx->res->default_message($status));返回$self->test('isnt’,$self->tx->res->code,$status,$desc);}子测试{my($self,$name,@args)=@_;本地$Test::Builder::Level=$Test:;返回$self->success(!!$self->处理程序->($name,@args));}子文本_is{my($self,$selector,$value,$desc)=@_;返回$self->test('is',$self->_text($selector),$value,_desc($desc,qq{与选择器“$selecter”}完全匹配);}子文本_isnt{my($self,$selector,$value,$desc)=@_;返回$self->test('isnt’,$self->_text($selector),$value,_desc($desc,qq{与选择器“$selecter”}不匹配);}子文本类{my($self,$selector,$regex,$desc)=@_;返回$self->test('like',$self->_text($selector),$regex,_desc($desc,qq{选择器“$selecter”}的类似匹配);}sub文本不同{my($self,$selector,$regex,$desc)=@_;$desc=_desc($desc,qq{选择器“$selector”}没有类似匹配项);返回$self->test(“不一样”,$self->_text($selector),$regex,$desc);}子websocket_ok{my$self=班次;返回$self->_request_ok($self->ua->build_websocket_tx(@_),$_[0]);}子属性(_A){my($self,$selector,$attr)=@_;返回unde,除非my$e=$self->tx->res->dom->at($selector);return$e->attr($attr)//“”;}子构建确定{my($self,$method,$url)=(移位,移位,移位);本地$Test::Builder::Level=$Test:;返回$self->_request_ok($self->ua->build_tx($method,$url,@_),$url);}sub _desc{编码'UTF-8',移位||shift}子处理程序(_H){my($name,@args)=@_;return测试::More->can($name)->(@args);}子_json{my($self,$method,$p)=@_;return Mojo::JSON::Pointer->new(j(@{$self->message//[]}[1]))->$method($p);}子消息(_M){my($self,$name,$value,$desc)=@_;本地$Test::Builder::Level=$Test:;my($type,$msg)=@{$self->消息//[]};#类型检查if(参考$value eq'HASH'){我的$expect=exists$value->{text}?'text“:”binary“;$value=$value->{$expect};$msg=“”,除非($type//'')eq$expect;}#如果没有类型检查,则解码文本框else{$msg=解码“UTF-8”,$msg if($type//'')eq“text”}return$self->test($name,$msg//'',$value,$desc);}子请求确定{my($self,$tx,$url)=@_;本地$Test::Builder::Level=$Test:;#建立WebSocket连接if($tx->req->ishandshake){@$self{qw(完成消息)}=(undef,[]);$self->ua->开始($tx=>子{my($ua,$tx)=@_;$self->{finished}=[]除非$self->tx($tx)->tx->is_websocket;$tx->on(finish=>sub{shift;$self->{finished}=[@_]});$tx->打开(二进制=>sub{push@{$self->{messages}},[binary=>pop]});$tx->打开(文本=>sub{push@{$self->{messages}},[text=>pop]});Mojo::IOLoop->停止;});Mojo::IOLoop->启动;return$self->测试('ok',$self->tx->is_websocket,_desc(“与$url握手的websocket”);}#执行请求$self->tx($self->ua->start($tx));我的$err=$self->tx->error;测试::更多::diag$err->{message}if!(我的$ok=!$err->{message}||$err->{code})&$err;return$self->test('ok',$ok,_desc(“@{[uc$tx->req->method]}$url”);}子文本(_T){返回undef,除非my$e=shift->tx->res->dom->at(shift);返回$e->text;}子等待(_W){my$self=班次;Mojo::IOLoop->one_tick while$self->{已完成}&&@{$self->{messages}};返回$self->message(shift@{$self->{messages}})->消息;}1;=编码utf8=头1名称测试::Mojo-测试Mojo=头1概述使用测试::更多;使用测试::Mojo;my$t=测试::Mojo->new(“MyApp”);#HTML/XML格式$t->get_ok('/welcome')->status_is(200)->text_is('div#message'=>'Hello!');#JSON格式$t->post_ok('/search.json'=>form=>{q=>'Perl'})->状态_ is(200)->header_is('Server'=>'Mojolicious(Perl)')->header_isnt('X-Bender'=>'咬我闪亮的金属屁股!')->json_is('/results/4/title'=>“Perl摇滚乐!”)->json_like('/results/7/title'=>qr/Perl/);#WebSocket$t->websocket_ok('/echo')->send_k(“你好”)->消息ok->message_is('echo:hello')->finish_ok;done_testing();=头1描述L(左)是基于L的测试用户代理,通常与L一起使用进行测试L(左)应用。用L运行测试即可.$证明-l-v$prove-l-vt/foo.t如果尚未定义,则C环境变量将设置为C或C,取决于关于C的值环境变量。为了更容易测试HTTPS/WSS web服务L(左)将默认为L激活.参见L了解更多信息。=头1属性L(左)实现以下属性。=head2处理程序我的$cb=$t->处理程序;$t=$t->处理程序(子{…});连接L的回调带L.$t->处理程序(子($name,@args){return测试::更多->can($name)->(@args);});=头2消息我的$msg=$t->消息;$t=$t->消息([文本=>$bytes]);当前WebSocket消息表示为包含帧类型和负载的数组引用。#更具体的测试使用Mojo::JSON qw(decode_JSON);我的$hash=解码json$t->message->[1];是ref$hash,'hash','right reference';是$hash->{foo},“bar”,“right value”;#测试自定义消息$t->消息([二进制=>$bytes])->json_message_has('/foo/bar')->json消息hasnt('/bar')->json消息is('/foo/baz'=>{yada=>[1,2,3]});=head2成功我的$bool=$t->成功;$t=$t->成功($bool);如果上次测试成功,则为True。#生成自定义测试my$location_is=sub($t,$value,$desc=''){$desc||=“位置:$value”;本地$Test::Builder::Level=$Test:;return$t->success(is($t->tx->res->headers->location,$value,$desc));};$t->get_ok('/')->状态(302)->$location_is('https://mojolicious.org')->或(子{diag“一定是Joel!”});=头部2 tx我的$tx=$t->tx;$t=$t->tx(Mojo::Transaction::HTTP->new);当前交易,通常为L或L对象。#更具体的测试是$t->tx->res->json->{foo},“bar”,“right value”;ok$t->tx->res->content->is-multipart,“多部分内容”;是$t->tx->previous->res->code,302,“正确状态”;=水头2 ua我的$ua=$t->ua;$t=$t->ua(Mojo::UserAgent->new);用于测试的用户代理,默认为L对象。#允许重定向$t->ua->max_redirects(10);$t->get_ok('/redirect')->status_is(200)->content_like(qr/redirected/);#将协议从HTTP切换到HTTPS$t->ua->server->url(“https”);$t->get_ok('/secure')->status_is(200)->content_like(qr/secure/);#对具有基本身份验证的请求使用绝对URL我的$url=$t->ua->server->url->userinfo('sri:secr3t')->path('/secrets.json');$t->post_ok($url=>json=>{limit=>10})->状态(200)->json_is('/1/content','Mojo rocks!');#自定义所有事务(包括后续重定向)$t->ua->打开(开始=>sub($ua,$tx){$tx->req->headers->accept_language('en-US')});$t->get_ok('/hello')->status_is(200)->content_like(qr/Howdy/);=头部1方法L(左)从L继承所有方法并实现了以下新功能。=head2应用程序我的$app=$t->app;$t=$t->app(Mojolicios->new);使用L访问应用程序.#更改日志级别$t->app->log->level(“目录”);#直接测试应用程序是$t->app->defaults->{foo},“bar”,“right value”;ok$t->app->routes->find('echo')->is_websocket,'websocket route';我的$c=$t->app->buildcontroller;ok$c->render(template=>'foo'),'渲染成功';是$c->res->status,200,“正确状态”;是$c->res->body,'Foo!','正确的内容';#更改应用程序行为$t->app->hook(before_dispatch=>sub($c)){如果$c->req->url->path->contains(“/user”);});$t->get_ok('/user')->status_is(200)->content_like(qr/not reach the router/);#提取其他信息我的$stash;$t->app->hook(after_dispatch=>sub($c){$stash=$c->stash});$t->get_ok('/hello')->status_is(200);是$stash->{foo},“bar”,“right value”;=头2 attr_is$t=$t->attr_is('img.cat','alt','Grumpy cat');$t=$t->attr_is('img.cat','alt','Grumpy cat','右alt文本');使用L检查属性的文本内容在CSS选择器的第一个匹配HTML/XML元素与L完全匹配.=头部2属性$t=$t->attr_isnt('img.cat','alt','Calm cat');$t=$t->attr_isnt('img.cat','alt','Calm-cat','different alt-text');L的对面.=头2属性类$t=$t->attr_like('img.cat','alt',qr/Grumpy/);$t=$t->attr_like('img.cat','alt',qr/Grumpy/,'right alt text');使用L检查属性的文本内容在CSS选择器的第一个匹配HTML/XML元素与L的相似匹配.=head2 attr_unliverse(头部2属性不同)$t=$t->attr_unlike('img.cat','alt',qr/Calm/);$t=$t->attr_unliverse('img.cat','alt',qr/Calm/,'different alt text');L的对面.=头2内容_is$t=$t->content_is('工作!');$t=$t->content_is('working!','right content');从L中检索响应内容后,检查其是否完全匹配.=头2内容$t=$t->content_isnt('工作!');$t=$t->content_isnt(“正在工作!”,“不同内容”);L的对面.=头2 content_like$t=$t->content_like(qr/working!/);$t=$t->content_like(qr/working!/,'right content');从L中检索响应内容后,检查类似匹配的响应内容.=头2 content_type_is$t=$t->content_type_is('text/html');$t=$t->content_type_is('text/html','正确的内容类型');检查响应C用于精确匹配的标题。=头2内容类型$t=$t->content_type_isnt('text/html');$t=$t->content_type_isnt('text/html','不同的内容类型');L的对面.=头2 content_type_like$t=$t->content_type_like(qr/text/);$t=$t->content_type_like(qr/text/,'正确的内容类型');检查响应C类似匹配的标题。=head2内容类型类似$t=$t->内容类型不同(qr/text/);$t=$t->content_type_unliverse(qr/text/,'不同的内容类型');L的对面.=head2内容不同$t=$t->内容不同(qr/working!/);$t=$t->content_unliverse(qr/working!/,'different content');L的对面.=头2删除(_ok)$t=$t->delete_ok('网址:http://example.com/foo');$t=$t->delete_ok('/foo');$t=$t->delete_ok('/foo'=>{Accept=>'*/*'}=>'内容!');$t=$t->delete_ok('/foo'=>{Accept=>'*/*'}=>form=>{a=>'b'});$t=$t->delete_ok('/foo'=>{Accept=>'*/*'}=>json=>{a=>'b'});执行C请求并检查传输错误,采用与L相同的参数,除了回叫。=头2元素_count_is$t=$t->element_count_is('div.foo[x=y]',5);$t=$t->element_count_is('html body div',30,'三十个元素');使用L检查CSS选择器匹配的HTML/XML元素数.=head2元素_exists$t=$t->元素存在('div.foo[x=y]');$t=$t->element_exists('html标题','有标题');检查CSS选择器是否存在,首先将HTML/XML元素与L匹配.#检查属性值$t->get_ok('/login')->元素存在('label[for=email])->元素存在('input[name=email][type=text][value*=“example.com”]')->元素存在('label[for=pass]')->元素存在('input[name=pass][type=password]')->element_exists('input[type=submit][value]);=头2元素_exists_not$t=$t->element_exists_not('div.foo[x=y]');$t=$t->element_exists_not('html标题','没有标题');L的对面.=头部2完成_ok$t=$t->finish_ok;$t=$t->finish_ok(1000);$t=$t->finish_ok(1003=>“无法接受数据!”);正常关闭WebSocket连接。=头部2已完成_ok$t=$t->finished_ok(1000);等待WebSocket连接正常关闭并检查状态。=头2获得确认$t=$t->get_ok('网址:http://example.com/foo');$t=$t->get_ok('/foo');$t=$t->get_ok('/foo'=>{Accept=>'*/*'}=>'内容!');$t=$t->get_ok('/foo'=>{Accept=>'*/*'}=>form=>{a=>'b'});$t=$t->get_ok('/foo'=>{Accept=>'*/*'}=>json=>{a=>'b'});执行C请求并检查传输错误,采用与L相同的参数,除用于回调。#对远程主机运行测试$t->get_ok('https://docs.mojolicious.org')->状态_is(200);#对具有基本身份验证的请求使用相对URL$t->get_ok('//sri:secr3t@/secrets.json')->状态_ is(200)->json_is('/1/content','Mojo rocks!');#对事务运行其他测试$t->get_ok('/foo')->status_is(200);是$t->tx->res->dom->at(‘input’)->val,‘whatever’,‘right value’;=头2头_ok$t=$t->head_ok('网址:http://example.com/foo');$t=$t->head_ok('/foo');$t=$t->head_ok('/foo'=>{Accept=>'*/*'}=>'内容!');$t=$t->head_ok('/foo'=>{Accept=>'*/*'}=>form=>{a=>'b'});$t=$t->head_ok('/foo'=>{Accept=>'*/*'}=>json=>{a=>'b'});执行C请求并检查传输错误,采用与L相同的参数,除用于回调。=head2 header_exists$t=$t->header_exists(“标记”);$t=$t->header_exists('ETag','header exists');检查响应标头是否存在。=头2 header_exists_not$t=$t->header_exists_not(“ETag”);$t=$t->header_exists_not('ETag','header is missing');L的对面.=head2 header_is$t=$t->header_is(ETag=>'“abc321”');$t=$t->header_is(ETag=>'“abc321”','右标题');检查响应标题是否完全匹配。=头2头_不是$t=$t->header_snt(Etag=>'“abc321”');$t=$t->header_isnt(ETag=>'“abc321”','不同的头');L的对面.=head2 header_like$t=$t->header_like(ETag=>qr/abc/);$t=$t->header_like(ETag=>qr/abc/,'右标题');检查响应标头是否存在类似匹配。=头2头_不同$t=$t->头部不同(ETag=>qr/abc/);$t=$t->header_unliverse(ETag=>qr/abc/,'不同的头');L的对面.=头2 json_has$t=$t->json_has('/foo');$t=$t->json_has('/minibar','has a minibar');检查JSON响应是否包含可以使用给定JSON指针识别的值L(左).=头部2 json_hasnt$t=$t->json_hasnt('/foo');$t=$t->json_hasnt('/minibar','no minibar');L的对面.=头2 json_is$t=$t->json_is({foo=>[1,2,3]});$t=$t->json_is('/foo'=>[1,2,3]);$t=$t->json_is('/foo/1'=>2,'正确值');使用带有L的给定JSON指针检查从JSON响应中提取的值,默认为如果省略,则返回根值。#使用空的JSON指针通过测试描述来测试整个JSON响应$t->json_is(''=>{foo=>[1,2,3]},'右对象');=头部2 json_like$t=$t->json_like('/foo/1'=>qr/^\d+$/);$t=$t->json_like('/foo/1'=>qr/^\d+$/,'右值');使用带有L的给定JSON指针检查从JSON响应中提取的值对于类似的匹配。=头2 json_message_has$t=$t->json_message_has('/foo');$t=$t->json_message_has('/minibar','has a minibar');检查JSON WebSocket消息是否包含可以使用给定的JSON指针标识的值L(左).=头2 json_message_hasnt$t=$t->json_message_hasnt('/foo');$t=$t->json_message_hasnt('/minibar','no minibar');L的对面.=头2 json_message_is$t=$t->json_message_is({foo=>[1,2,3]});$t=$t->json_message_is('/foo'=>[1,2,3]);$t=$t->json_message_is('/foo/1'=>2,'正确值');使用带有L的给定JSON指针检查从JSON WebSocket消息中提取的值,其中如果省略,则默认为根值。=头2 json_message_like$t=$t->json_message_like('/foo/1'=>qr/^\d+$/);$t=$t->json_message_like('/foo/1'=>qr/^\d+$/,'正确值');使用带有L的给定JSON指针检查从JSON WebSocket消息中提取的值对于类似的匹配。=头2 json消息不同$t=$t->json消息不一样('/foo/1'=>qr/^\d+$/);$t=$t->json_message_unliverse('/foo/1'=>qr/^\d+$/,'不同的值');L的对面.=head2 json_unlike$t=$t->json_unliverse('/foo/1'=>qr/^\d+$/);$t=$t->json_unliverse('/foo/1'=>qr/^\d+$/,'不同的值');L的对面.=头2消息$t=$t->message_is({binary=>$bytes});$t=$t->message_is({text=>$bytes});$t=$t->message_is(“正在工作!”);$t=$t->message_is('工作!','正确的消息');检查WebSocket消息是否完全匹配。=头2消息$t=$t->message_isnt({binary=>$bytes});$t=$t->message_isnt({text=>$bytes});$t=$t->message_isnt('工作!');$t=$t->message_isnt('工作!','不同的消息');L的对面.=头2消息类$t=$t->message_like({binary=>qr/$bytes/});$t=$t->message_like({text=>qr/$bytes/});$t=$t->message_like(qr/正在工作!/);$t=$t->message_like(qr/working!/,'正确的消息');检查WebSocket消息是否存在类似匹配。=头2消息_ok$t=$t->message_ok;$t=$t->message_k('收到消息');等待下一条WebSocket消息到达。#等待消息并对其执行多项测试$t->websocket_ok('/time')->消息_ok->类消息(qr/\d+/)->消息不同(qr/\w+/)->finish_ok;=头2消息不同$t=$t->message_difference({binary=>qr/$bytes/});$t=$t->message_difference({text=>qr/$bytes/});$t=$t->消息不同(qr/working!/);$t=$t->message_unliverse(qr/working!/,'不同的消息');L的对面.=头部2新my$t=测试::Mojo->new;my$t=测试::Mojo->new(“MyApp”);my$t=Test::Mojo->new('MyApp',{foo=>'bar'});my$t=Test::Mojo->new(Mojo::File->new('/path/to/myapp.pl'));my$t=Test::Mojo->new(Mojo::File->new('/path/to/myapp.pl'),{foo=>'bar'});my$t=测试::Mojo->new(MyApp->new);my$t=测试::Mojo->new(MyApp->new,{foo=>‘bar’});构造一个新的L对象。除了类名或L之外指向应用程序的对象脚本中,您可以传递带有配置值的散列引用,这些配置值将用于覆盖应用程序配置。特殊配置值C将设置为L还有,其中用于禁用配置插件,如L,LL(左)用于测试。#加载相对于“t”目录的应用程序脚本使用Mojo::文件qw(curfile);my$t=测试::Mojo->new(curfile->目录名->同级('myapp.pl'));=头2选项_ok$t=$t->options_ok('网址:http://example.com/foo');$t=$t->options_ok('/foo');$t=$t->options_ok('/foo'=>{Accept=>'*/*'}=>'内容!');$t=$t->options_ok('/foo'=>{Accept=>'*/*'}=>form=>{a=>'b'});$t=$t->options_ok('/foo'=>{Accept=>'*/*'}=>json=>{a=>'b'});执行C请求并检查传输错误,采用与L相同的参数,除了回叫。=头部2或$t=$t->或(子{…});如果L的值为为false。#诊断$t->get_ok('/bad')->或(sub{diag'一定是Glen!'})->状态_is(200)->或(子{diag$t->tx->res->dom->at(“标题”)->文本});=头2 patch_ok$t=$t->patch_ok('网址:http://example.com/foo');$t=$t->patch_ok('/foo');$t=$t->patch_ok('/foo'=>{Accept=>'*/*'}=>'内容!');$t=$t->patch_ok('/foo'=>{Accept=>'*/*'}=>form=>{a=>'b'});$t=$t->patch_ok('/foo'=>{Accept=>'*/*'}=>json=>{a=>'b'});执行C请求并检查传输错误,采用与L相同的参数,除了回调。=头部2 post_ok$t=$t->post_ok('网址:http://example.com/foo');$t=$t->post_ok('/foo');$t=$t->post_ok('/foo'=>{Accept=>'*/*'}=>'内容!');$t=$t->post_ok('/foo'=>{Accept=>'*/*'}=>form=>{a=>'b'});$t=$t->post_ok('/foo'=>{Accept=>'*/*'}=>json=>{a=>'b'});执行C请求并检查传输错误,采用与L相同的参数,除用于回调。#测试文件上传my$upload={foo=>{content=>'bar',filename=>'baz.txt'}};$t->post_ok('/upload'=>表单=>$upload)->status_is(200);#测试JSON API$t->post_ok('/hello.json'=>json=>{hello=>'world'})->状态_ is(200)->json_is({bye=>“世界”});=头部2 put_ok$t=$t->put_ok('网址:http://example.com/foo');$t=$t->put_ok('/foo');$t=$t->put_ok('/foo'=>{Accept=>'*/*'}=>'内容!');$t=$t->put_ok('/foo'=>{Accept=>'*/*'}=>form=>{a=>'b'});$t=$t->put_ok('/foo'=>{Accept=>'*/*'}=>json=>{a=>'b'});执行C请求并检查传输错误,采用与L相同的参数,除用于回调。=头2请求_确定$t=$t->request_ok(Mojo::Transaction::HTTP->new);执行请求并检查传输错误。#使用自定义方法请求我的$tx=$t->ua->build_tx(FOO=>'/test.json'=>json=>{FOO=>1});$t->request_ok($tx)->status_is(200)->json_is({success=>1});#带有自定义cookie的请求我的$tx=$t->ua->build_tx(GET=>'/account');$tx->req->cookie({name=>'user',value=>'sri'});$t->request_ok($tx)->status_is(200)->text_is('head>title'=>'Hello sri');#自定义WebSocket握手我的$tx=$t->ua->build_websocket_tx('/foo');$tx->req->headers->remove(“用户代理”);$t->request_ok($tx)->message_k->message_is('bar')->finish_ok;=头2重置会话$t=$t->重置会话;重置用户代理会话。=头2 send_ok$t=$t->send_k({binary=>$bytes});$t=$t->send_ok({text=>$bytes});$t=$t->send_k({json=>{test=>[1,2,3]}});$t=$t->send_ok([$fin,$rsv1,$rsv2,$rsv3,$op,$payload]);$t=$t->send_ok($chars);$t=$t->send_ok($chars,'发送成功');通过WebSocket发送消息或帧。#以“文本”消息形式发送JSON对象$t->websocket_ok('/echo.json')->send_ok({json=>{test=>'IMojolicious!“}})->消息_ok->json_message_is('/test'=>'IMojolicious!”)->finish_ok;=头2状态$t=$t->status_is(200);$t=$t->status_is(200,‘正确状态’);检查响应状态是否完全匹配。=头部2状态$t=$t->status_isnt(200);$t=$t->status_isnt(200,'不同状态');L的对面.=头部2测试$t=$t->测试('is','first value','second value','right value');致电L通过L的函数,用于实现L角色。结果将存储在L(左).=头2 text_is$t=$t->text_is('div.foo[x=y]'=>“你好!”);$t=$t->text_is('html标题'=>'你好!','右标题');首先检查与HTML/XML元素匹配的CSS选择器的文本内容是否与L完全匹配.=头2 text_isnt$t=$t->text_isnt('div.foo[x=y]'=>“你好!”);$t=$t->text_isnt('html head title'=>'Hello!','different title');L的对面.=头2 text_like$t=$t->text_like('div.foo[x=y]'=>qr/Hello/);$t=$t->text_like('html标题'=>qr/Hello/,'right title');首先检查与HTML/XML元素匹配的CSS选择器的文本内容是否与L相似.=头部2 text_unlike$t=$t->text_unlike('div.foo[x=y]'=>qr/你好/);$t=$t->text_unlike('html标题'=>qr/Hello/,'不同标题');L的对面.=头2 websocket_ok$t=$t->websocket_ok('http://example.com/echo');$t=$t->websocket_ok('/echo');$t=$t->websocket_ok('/echo'=>{DNT=>1}=>['v1.proto']);使用透明握手打开WebSocket连接,使用与L相同的参数,除了回叫。#具有permessage-deflate压缩的WebSocket$t->websocket_ok('/'=>{“Sec-websocket-Extensions”=>“permessage-deflate”})->发送(“y”x 50000)->消息_ok->消息('z'x 50000)->finish_ok;=头部1另见L(左),L,L.=切割