其实每次请求的区别就是$_GET、$_POST、$_COOKIE、$_SERVER这些环境数据在发生改变,所以只要改变这些环境数据再执行Controller就能够模拟请求了
我用单元测试的方式来实现,代码大概就是下面这个样子,其实每次模拟请求就是通过router去执行controller类的不同方法而已
还可以使用phpunit --process-isolation参数把每次测试放到单独的php进程里执行,避免某些代码逻辑反复执行导致的状态污染问题
PHP/**
* @example
* $this->execute(array(
* 'path' => '/foo/bar',
* 'method' => 'GET',
* 'get' => array(),
* 'post' => array(),
* 'headers' => array(
* 'Content-Type' => 'text/html'
* ),
* ));
*/
protected function execute(array $options) {
if (!isset($options['path'])) {
$options['path'] = $this->path;
}
$_SERVER = array();
$_GET = $_POST = array();
$_SERVER['REQUEST_URI'] = isset($options['path']) ? $options['path'] : '/';
$method = isset($options['method']) ? strtoupper($options['method']) : 'GET';
$_SERVER['REQUEST_METHOD'] = $method;
if (isset($options['get'])) {
$_GET = $options['get'];
}
if (isset($options['post'])) {
$_POST = $options['post'];
}
$headers = isset($options['headers']) ? $options['headers'] : array();
foreach ($headers as $key => $value) {
$key = 'HTTP_'.strtoupper(str_replace('-', '_', $key));
$_SERVER[$key] = $value;
}
return $this->router->execute();
}