— 自动化测试过程中常规策略 一.背景 Session称为会话,是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间,如果需要的话,可能还有一定的操作空间。通常情况下Session用于存储需要在整个用户会话过程中
— 自动化测试过程中常规策略
Session称为会话,是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间,如果需要的话,可能还有一定的操作空间。通常情况下Session用于存储需要在整个用户会话过程中保持其状态的信息,例如登录信息或用户浏览 Web应用程序时需要的其它信息。
PHP的 $_SESSION 的功能之所以如此强大是因为有WebServer的支持,试想一下如果在命令行下读取一个 $_SESSION 变量,会是什么结果?
必然是null,因为PHP的session_start() 函数在命令行下是无法使用的,假若一段逻辑结果中含有这个Session会话变量,该如何去测试它的有效性?
为了探究WebServer下的Session原理,我们做一个简单的测试:
<?php session_start();
Cookie中存在一个PHPSESSID的值,而 /tmp/ 下存在一个对应的值,同时还可以知道这个 /tmp/sess_87bufd4ogid71e1gr6dtcbphi0是刚刚建立的,并且文件大小是0。
session_start(); $_SESSION['login'] = 1; $_SESSION['name'] = 'Lancer He'; $_SESSION['uid'] = 72; $_SESSION['groups'] = array( "dev" => 2, "loc" => 4, );
再观察浏览器的Request Header中的cookie信息依旧不变,但是却可以发现服务器下 /tmp/sess_87bufd4ogid71e1gr6dtcbphi0文件的大小更变,打开发现类似序列化(非序列化)的字符串,信息内容是之前$_SESSION的值:
观察新出现一个以sess为前缀的文件,同时IE的Cookie下出现了这个PHPSESSID的值。
既然Session的默认机制是存放在文件中,因此我们是不是可以为了命令行模式做一个假的Session机制,因此不妨设计一个策略模式:
让我们做这样简单的操作,无论在CLI模式或是Http模式都能正常运行:
\Cores\Session::getInstance()->set('name', "Lancer"); \Cores\Session::getInstance()->set('age', "28"); \Cores\Session::getInstance()->del("age"); \Cores\Session::getInstance()->has("name") \Cores\Session::getInstance()->has("groups", array( "dev" => 2, "loc" => 4, ));
我们可以猜想到:
\Cores\Session对象的 getInstance() 方法必然是一个自动选择策略的过程,返回的是一个对象:
既然是一种策略模式, \Cores\Session_CLI 与 \Cores\Session_Http 必须拥有同样的方法来操作Session,所以需要提供一个接口 \Cores\Session_Interface 。
根据我们的想法,设计出简单的UML图,Session具有基本的五个方法:
start(开始), set(赋值), has(存在), get(获取), del(删除)
由于Session启动后在整个应用中必然是唯一实例,因此上图 \Cores\Session_CLI 与 \Cores\Session_Http都使用了单例模式,但 \Cores\Session_CLI 必须具有一些特殊的操作,比如写入session记录,创建session_id等伪操作,因此添加部分方法:
根据Session策略设计,开始编写对应的类:
/** * Session接口 * @author Lancer He <lancer.he> * @since 2014-04-23 * @copyright http://www.crackedzone.com */ interface Session_Interface { // 开启 public function start(); // 是否存在某个Session public function has($name); // 获取某个Session public function get($name=''); // 给某个Session赋值 public function set($name, $value); // 删除某个Session值 public function del($name); }</lancer.he>
/** * Http模式下管理$_SESSION类 * @author Lancer He <lancer.he> * @since 2014-04-23 * @copyright http://www.crackedzone.com */ class Session_Http { protected static $_instance = null; /** * session是否已经开启 * @var boolean */ protected $_started = false; /** * 单例模式禁止Clone */ private function __clone() {} /** * 单例模式禁止外部初始化 */ private function __construct() {} /** * 返回单例模式 */ public static function getInstance() { if ( ! is_null( self::$_instance ) ) { return self::$_instance; } $instance = new self(); $instance->start(); self::$_instance = $instance; return $instance; } /** * 开启Session * @return void */ public function start() { session_start(); $this->_started = true; } /** * 通过name查看Session是否存在 * @param string $name * @return boolean */ public function has($name) { return isset($_SESSION[$name]); } /** * 通过name从Session中获取一个值 * @param string $name 为空时返回整个sessino * @return mixed */ public function get($name='') { if ( ! $name ) return $_SESSION; return isset($_SESSION[$name]) ? $_SESSION[$name] : null; } /** * 给指定的name设置一个session值,返回连缀对象 * @param string $name * @param mixed $value * @return object */ public function set($name, $value) { $_SESSION[$name] = $value; return $this; } /** * 从session中删除一个值,失败返回false,成功返回连缀对象 * @param string $name * @return false|object */ public function del($name) { if ( ! $this->has($name) ) return false; unset($_SESSION[$name]); return $this; } }</lancer.he>
/** * CLI模式下会模拟一个session_id,同时在/tmp/下产生一个sesscli文件用来保存session信息 * @author Lancer He <lancer.he> * @since 2014-04-23 * @copyright http://www.crackedzone.com */ class Session_Cli { protected static $_instance = null; /** * session_id * @var string */ protected $_session_id = null; /** * session file * @var string */ protected $_session_file = null; /** * session数组 * @var array */ protected $_session = array(); /** * session是否已经开启 * @var boolean */ protected $_started = false; /** * 单例模式禁止Clone */ private function __clone() {} /** * 单例模式禁止外部初始化 */ private function __construct() {} /** * 返回单例模式 */ public static function getInstance() { if ( ! is_null( self::$_instance ) ) { return self::$_instance; } $instance = new self(); $instance->start(); self::$_instance = $instance; return $instance; } /** * 开启Session * @return void */ public function start() { $this->_init(); $this->_started = true; } /** * 初始session * @return void */ protected function _init() { $this->_session_id = md5(uniqid()); $this->_session_file = '/tmp/' . APPLICATION_CLI_SESSION_FILE_PREFIX . $this->_session_id; if ( file_exists($this->_session_file) ) { $this->_session = unserialize( file_get_contents($this->_session_file) ); return; } file_put_contents($this->_session_file, null); } /** * 通过name查看Session是否存在 * @param string $name * @return boolean */ public function has($name) { return isset($this->_session[$name]); } /** * 通过name从Session中获取一个值 * @param string $name 为空时返回整个sessino * @return mixed */ public function get($name='') { if ( ! $name ) return $this->_session; return isset($this->_session[$name]) ? $this->_session[$name] : null; } /** * 给指定的name设置一个session值,返回连缀对象 * @param string $name * @param mixed $value * @return object */ public function set($name, $value) { $this->_session[$name] = $value; return $this; } /** * 从session中删除一个值,失败返回false,成功返回连缀对象 * @param string $name * @return false|object */ public function del($name) { if ( ! $this->has($name) ) return false; unset($this->_session[$name]); return $this; } /** * 将session存放到tmp文件中 * @return void */ public function __destruct() { file_put_contents($this->_session_file, serialize($this->_session) ); } }</lancer.he>
由于具体策略类已经完成,所以我们只需要定义一个常量用于区分是否是CLI请求,同样使用单例模式自动装载对应的具体策略。
class Session { public static function getInstance() { return APPLICATION_IS_CLI ? Session_Cli::getInstance() : Session_Http::getInstance(); } }
Cli测试结果:
Http测试结果:
虽然保存在 /tmp/ 目录下的内容格式不一致,但已经模拟出一个Session仓库的功能,实现了对这个仓库的增删改查功能。
通过策略模式模拟一个虚拟的Session功能,保证Session在命令行下能够正常工作,为项目的自动化测试提供了基本支持。
策略模式其用意在于封装了一组新的算法,基于不同的策略下能够互相替换,为此我们能够在自动化测试中模拟出更多的功能,如请求的Request功能,渲染的View功能等。
原文标题:PHP命令行下模拟Session机制
原文地址:http://www.crackedzone.com/php-cli-using-session-strategy.html