原文地址: Laravel 5.1 Beauty - Testingjavascript
Note 本系列第四节内容.php
本章会建立一个之后能够用到的项目便于之后咱们的课程使用, 同时也会查课各类测试选项. 之后一段时间内会开发一个 Markdown 文本转换成 Html 的服务信息.css
根据以前的章节 Six Steps to Starting a New Laravel 5.1 Project 建立 l5beauty 项目下面所示项目java
首先在你的系统安装 app 框架node
$ laravel new l5beauty Crafting application... Generating optimized class loader Compiling common classes Application key [rzUhyDksVxzTXFjzFYiOWToqpunI2m6X] set successfully. Application ready! Build something amazing.
接下来设置 l5beauty.app
做为虚拟主机.mysql
$ serve l5beauty.app ~/l5beauty/public dos2unix: converting file /vagrant/scripts/serve.sh to Unix format ... * Restarting nginx nginx [ OK ] php5-fpm stop/waiting php5-fpm start/running, process 2169
回到主机, 添加如下记录到映射文件nginx
192.168.10.10 l5beauty.app
从主机中, 按照如下步骤安装 NPM 本地包laravel
$ cd l5beauty $ npm install | > node-sass@2.0.1 install /Users/chuck/Code/l5beauty/node_modules/laravel-\ elixir/node_modules/gulp-sass/node_modules/node-sass > node scripts/install.js > node-sass@2.0.1 postinstall /Users/chuck/Code/l5beauty/node_modules/\ laravel-elixir/node_modules/gulp-sass/node_modules/node-sass > node scripts/build.js `darwin-x64-node-0.10` exists; testing Binary is fine; exiting gulp@3.8.11 node_modules/gulp ├── v8flags@2.0.2 ├── pretty-hrtime@0.2.2 [snip]
回到主机, 建立数据库git
$ mysql --user=homestead --password=secret mysql> create database l5beauty; Query OK, 1 row affected (0.00 sec) mysql> exit; Bye
编辑 .env
文件, 修改数据库为 l5beauty
.github
// Change the following line DB_DATABASE=homestead // To the correct value DB_DATABASE=l5beauty
最后, 访问 http://l5beauty.app
, 确保一切可用.
Figure 6.1 - Step 5 - 在浏览器中测试
Laravel 5.1 已经准备好测试了, 有个最简单的方式来检测一个访问是否返回200响应.
运行 PHPUnit , 简单的在根目录上执行 phpunit
就OK
$ cd l5beauty ~/l5beauty $ phpunit PHPUnit 4.7.4 by Sebastian Bergmann and contributors. Time: 544 ms, Memory: 10.25Mb OK (1 test, 2 assertions)
若是你在运行 phpunit
收到 command not found 或者 permissions denied 错误提示, 有多是由于安装问题. phpunit
命令通常会存放在 vendor/bin
目录而且添加进系统变量, 问题是 Laravel 命令有一个bug是没有给这个命令设置相应的权限
使用以下方法解决这个问题:
Step 1 - 删除 vendor
目录
Step 2 - 在代码根目录使用 composer update
命令从新建立 vendor
目录. (操做系统中运行)
这样, 而后从新执行 phpunit
在 Laravel 5.1 项目根目录中有个文件 phpunit.xml
. 这个文件包含使用 phpunit
运行时候的配置
phpunit.xml
的测试会放置在 tests
目录, 这里有两个文件
ExampleTest.php
- 包含一个测试方法 testBasicExample()
. 这个 ExampleTest
类集成自 TestCase
类.TestCase.php
- Laravel 基础测试单元.查看 testBasicExample()
方法 ExampleTest.php
.
public function testBasicExample() { $this->visit('/') ->see('Laravel 5'); }
这个测试告诉咱们 "访问主页而且可以看到内容 ‘Laravel 5’", 还能比这个更简洁么 ?
TestCase
类提供在框架中的应用方法和属性. TestCase
一样提供了一个附加断言列表方法和 crawler 类型测试
Crawler 容许你测试web应用. 这些方法都有个统一的优势就是都可以返回 $this
, 容许你建立 ->visit()->see()
相似这样的链式调用.
下边是一些属性和方法:
$this->response
web应用返回的最后的响应
$this->currentUri
当前查看的Uri
visit($uri)
(Fluent) 使用 get 方法访问给定的uri
get($uri, array $headers = [])
(Fluent) 使用 get 方法访问url, 并能够传输给定的header
post($uri, array $data = [], array $headers = [])
(Fluent) post 请求
put($uri, array $data = [], array $headers = [])
(Fluent) put 请求
patch($uri, array $data = [], array $headers = [])
(Fluent) PATCH 请求
delete($uri, array $data = [], array $headers = [])
(Fluent) DELETE 请求
followRedirects()
(Fluent) 跟踪最近返回的重定向
see($text, $negate = false)
(Fluent) 查找页面上显示的内容/显示/不显示
seeJson(array $data = null)
(Fluent) 断定请求包含 json, 若是传输了 $data
参数, json 值必须匹配.
seeStatusCode($status)
(Fluent) 相应是否返回指定的状态码
seePageIs($uri)
(Fluent) 当前页面是不是指定的URI
seeOnPage($uri)
and landOn($uri)
(Fluent) Alias seePageIs()
click($name)
(Fluent) 经过name 或者 id 来请求点击
type($text, $element)
(Fluent) 填充自定义的文本
check($element)
(Fluent) 检测页面的checkbox
select($option, $element)
(Fluent) 选择下拉项
attach($absolutePath, $element)
(Fluent) 附件
press($buttonText)
(Fluent) 提交指定文本的text
withoutMiddleware()
(Fluent) 禁用 middleware
dump()
输入最近返回的内容
这里有额外的 Laravel 5.1 方法和属性
$app
$app 实例
$code
artisan 返回的最近的 code 码
refreshApplication()
刷新应用, setup()方法会自动调用这个方法.
call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
调用指定的url 而且返回响应.
callSecure($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
调用 https 访问url而且返回响应
action($method, $action, $wildcards = [], $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
调用控制器方法
route($method, $name, $routeParameters = [], $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
调用路由而且返回方法.
instance($abstract, $object)
注册对象的实例
expectsEvents($events)
指定可能被触发的事件列表.
withoutEvents()
不调用事件
expectsJobs($jobs)
注册队列
withSession(array $data)
使用session
session(array $data)
开始并设置 session
flushSession()
刷新当前session 的内容
startSession()
开始 session
actingAs($user)
(Fluent) 设置当前登陆的用户
be($user)
设置用户
seeInDatabase($table, array $data, $connection = null)
(Fluent) 检测给定的数据是否存在在数据库中
notSeeInDatabase($table, $array $data, $connection = null)
(Fluent) 检测数据是否不存在数据库中
missingFromDatabase($table, array $data, $connection = null)
(Fluent) Alias notSeeInDatabase()
.
seed()
数据库数据seed 生成器
artisan($command, $parameters = [])
指定 artisan 命令而且返回代码
上边的方法/属性都可以在 test 中 使用, 默认的 ExampleTest.php
中存在一个方法 testBasicExample()
, 这个调用了 $this->call(...)
方法.
除了标准的 PHPUnit 断言(assertEquals()
, assertContains()
, assertInstanceOf()
, ...)以外, 还存在不少容许测试 web 应用的检测项目
assertPageLoaded($uri, $message = null)
检测最近的页面是否被加载, 若是不存在 url / message 时候会报错
assertResponseOk()
是否页面相应OK
assertReponseStatus($code)
是否响应指定的code
assertViewHas($key, $value = null)
视图中是否存在指定的数据
assertViewHasAll($bindings)
视图中是否存在指定的一系列数据
assertViewMissing($key)
指定视图中是否不存在这个数据
assertRedirectedTo($uri, $with = [])
检测是否重定向到指定的uri
assertRedirectedToRoute($name, $parameters = [], $with = [])
是否客户端重定向到指定的路由
assertRedirectedToAction($name, $parameters = [], $with = [])
是否重定向到 action
assertSessionHas($key, $value = null)
session 中是否存在 key/ value
assertSessionHasAll($bindings)
session 中是否存在指定的 kv
assertSessionHasErrors($bindings = [])
session 是否存在错误
assertHasOldInput()
session 中是否存在之前的数据
Gulp 是用javascript 写成的编译和自动化工具. 基本用来最小化源代码或者从源代码生成文件. Gulp 可以监控源代码的改变而且自动运行指定的任务
Laravel 5.1 存在 Laravel Elixir 容许运行 gulp 任务. Elixir 加入了更简洁的语法. 你这样想 PHP 中的 Laravel, Gulp 中的 Elixir.
一个最经常使用的 Gulp 是自动化测试. 咱们根据 TDD (Test Driven Development) 来自动化运行咱们的测试任务.
首先, 编辑 gulpfile.js
文件, 并按照如下修改.
var elixir = require('laravel-elixir'); elixir(function(mix) { mix.phpUnit(); });
这里咱们调用 elixir()
方法. 传递一个函数. 这个函数接收一个 mix 对象. 这个函数可以干不少你可能想都想不到的事情. 你可能想经过 less 文件编译 css 文件. 而后合并 css 文件, 而后再文件末尾加缀上版本号. 全部的这些事情均可以经过 mix
对象来运行.
可是如今, 咱们仅仅运行 PHPUnit 测试.
接下来, 直接运行 glup
~% cd Code/l5beauty ~/Code/l5beauty% gulp [15:26:23] Using gulpfile ~/Code/l5beauty/gulpfile.js [15:26:23] Starting 'default'... [15:26:23] Starting 'phpunit'... [15:26:25] Finished 'default' after 2.15 s [15:26:25] *** Debug Cmd: ./vendor/bin/phpunit --colors --debug *** [15:26:28] PHPUnit 4.7.4 by Sebastian Bergmann and contributors. Configuration read from /Users/chuck/Code/l5beauty/phpunit.xml Starting test 'ExampleTest::testBasicExample'. Time: 2.07 seconds, Memory: 10.25Mb OK (1 test, 2 assertions) [15:26:28] gulp-notify: [Green!] [15:26:28] Finished 'phpunit' after 4.96 s
你可能收到一个通知, 一个弹框, 绿色告知你全部测试都已经经过了
Figure 6.2 - Gulp’s PHPUnit Success on Windows 8.1
想要使用 gulp进行自动化测试, 运行 gulp tdd
~% cd Code/l5beauty ~/Code/l5beauty% gulp tdd [15:29:49] Using gulpfile ~/Code/l5beauty/gulpfile.js [15:29:49] Starting 'tdd'... [15:29:49] Finished 'tdd' after 21 ms
这个命令挂载在这里, 监听源文件的变化, 而且在须要的时候进行单元测试.
想要查看如何运行的. 让咱们中段存在的单元测试.
改变 tests/ExampleTest.php
的 see()
方法.
->see('Laravel 5x');
当你保存这个文件, gulp 将会通知而且从新运行 PHPUnit , 这个将会执行错误. 而后你会看到一个红色的错误提示
Figure 6.3 - Gulp’s PHPUnit Failure on Mac
若是你要从新更改回来,保存, 而后 gulp 会从新运行 PHPUnit, 而后你会看到绿色的图标
按下 Ctrl+C
在博客应用中咱们会使用 Markdown 语法来写文章, 若是你不熟悉 markdown, 能够经过链接来检查这个语法, 这是一个快速读/写而且可以保存为 HTML.
举例说明, 咱们会建立一个服务项目来生成HTML.
这里有许多的PHP包来把markdown 转换为HTML, 若是你去 http://packagist.org
这里搜索 markdown , 会发现 20 多页的包.
咱们会使用 Michel Fortin 建立的包. 由于"好", 接下来咱们运行以下的命令来拉取这个包
~/Code/l5beauty% composer require michelf/php-markdown Using version ^1.5 for michelf/php-markdown ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) - Installing michelf/php-markdown (1.5.0) Downloading: 100% Writing lock file Generating autoload files Generating optimized class loader ~/Code/l5beauty% composer require "michelf/php-smartypants=1.6.0-beta1" ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) - Installing michelf/php-smartypants (1.6.0-beta1) Loading from cache Writing lock file Generating autoload files Generating optimized class loader
你有没有注意到指定了包版本号. 这是由于写这篇文章的时候尚未一个稳定的版本号可以自动拉取到
开始 TDD session 的第一件事就是开启 TDD 模式
~/Code/l5beauty% gulp tdd [19:41:38] Using gulpfile ~/Code/l5beauty/gulpfile.js [19:41:38] Starting 'tdd'... [19:41:38] Finished 'tdd' after 23 ms
如今 gulp 监控 PHPUnit 的改变. 让咱们建立测试类
在 tests
目录, 建立一个新文件夹命名为 Services
同时建立一个文件 MarkdownerTest.php
<?php class MarkdownerTest extends TestCase { # 保存 markdown 对象 protected $markdown; # 建立 Markdowner 对象 public function setup() { $this->markdown = new \App\Services\Markdowner(); } # 测试 public function testSimpleParagraph() { $this->assertEquals( "<p>test</p>\n", $this->markdown->toHTML('test') ); } }
这里会报错
即便告诉你检测失败, 日志中也会存在相应的错误日志, 这里很明显的是 App\Services\Markdowner
这个类不存在.
这里咱们建立一个服务来封装 php-markdown 和 php-smartypants 来加载导入的服务
在 app\Services
目录建立一个 Markdowner.php
服务并填写如下的内容 .
<?php # 命名空间 namespace App\Services; # 导入的类 use Michelf\MarkdownExtra; use Michelf\SmartyPants; class Markdowner { # 转换类 public function toHTML($text) { $text = $this->preTransformText($text); $text = MarkdownExtra::defaultTransform($text); $text = SmartyPants::defaultTransform($text); $text = $this->postTransformText($text); return $text; } protected function preTransformText($text) { return $text; } protected function postTransformText($text) { return $text; } }
当你保存了这个文件, Gulp 应当显示一个绿色的提示框. 告诉你执行OK.
若是你没有收到绿色的提示. 检测文件和测试类.
你们都赞成的是, 这不是一个好的 TDD 测试例子, 由于太简单了. 实际的会有好多操做步骤和迭代, 以下
目前为止, 全部的咱们 Markdowner
类在测试前都是不完整的.要在该类上进行 纯 单元测试,应该将其结构化以便将 MarkdownExtra
和 SmartyPants
类的实例注入到构造函数中, 经过这种方式咱们的单元测试能够注入模拟对象,而且只验证 MarkdownExtra
的行为,而不是它所调用的类.
但这不是一本关于测试的书。事实上,这是讨论测试的唯一一章。咱们会离开这个结构,但须要再添加几个测试。
更新 MarkdownerTest
来和下面的内容一致
<?php class MarkdownerTest extends TestCase { protected $markdown; public function setup() { $this->markdown = new \App\Services\Markdowner(); } /** * @dataProvider conversionsProvider */ public function testConversions($value, $expected) { $this->assertEquals($expected, $this->markdown->toHTML($value)); } public function conversionsProvider() { return [ ["test", "<p>test</p>\n"], ["# title", "<h1>title</h1>\n"], ["Here's Johnny!", "<p>Here’s Johnny!</p>\n"], ]; } }
在这里,咱们更改了测试类用来一次测试多个转换,并在 conversionsProvider()
中添加了三个测试。在进行下一步骤以前,你的测试结果应该是绿色的。
在系统控制台中一旦测试是绿色的,按 Ctrl+C
来中止 Gulp
这里并非想使用 Laravel 5.1
提供一个完整的测试方法,由于在PHP中没有单独的方法来进行测试。
所以,在 Laravel 5 5.1 中没有单一的测试方法。
可是,咱们将探索一些替代方案
除了 PHPUnit ,Laravel 5.1 还提供了 phpspec 。这是另外一种流行的PHP测试,它更多地关注于 BDD(行为驱动开发)
这里有一些关于phpspec的注释。
vendor/bin
, 所以你能够在项目根目录下调用 phpspec
.phpspec.yml
.phpSpec()
函数, 你能够在 mix
对象中运行.App
改为其余的命名空间, 确保同步更新 phpspec.yml
中的配置.虽然 PHPUnit 是 PHP 单元测试的标准,但也有其余的包可使用
这些测试真实的使用了您的应用程序,而不是仅仅验证您的应用程序中的代码单元。当使用流畅的测试方法 Laravel 5.1 时,你可使用 PHPUnit 进行一些功能测试. ExampleTest.php
提供了一个简单的示例. 可是也有其余的测试框架关注于功能/验收测试(functional / acceptance testing).
BDD(行为驱动开发)有两种方式: SpecBDD 和 StoryBDD
SpecDD 关注代码的技术方面。Laravel 5.1 包含了 _phpspec_, 这是SpecDD的标准
StoryBDD 强调业务或特性测试. Behat 是最流行的 StoryBDD 框架。一样 Codeception 也能够用于 StoryBDD 。
咱们在这一章所作的第一件事就是建立一个名为 l5beauty 的项目。而后咱们在这个项目中使用 PHPUnit 进行单元测试。最后,咱们建立了一个 Markdowner
服务类,这有两个目的 一是测试, 二是并在之后将 markdown 转换为 HTML 。
这是一个至关长的章节,由于测试是一个很大的话题,而一个章节没法给出公正的评价。可是,正如我所提到的,测试并非本书的重点。在随后的章节中,将再也不进行测试。
下一章咱们讨论一些如何让系统更快的话题如何?