Skip to content

Instantly share code, notes, and snippets.

@picasso250
Last active March 30, 2018 07:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save picasso250/562a044148ab175cb9ef78d2a2f4fbd3 to your computer and use it in GitHub Desktop.
Save picasso250/562a044148ab175cb9ef78d2a2f4fbd3 to your computer and use it in GitHub Desktop.
a small behavior test framework for php
<?php
if (!isset($argv[1])) {
echo "Usage: $argv[0] test_file\n";
exit();
}
$_cur_test_file = $argv[1];
if (!is_file($_cur_test_file)) {
echo "$_cur_test_file not exits\n";
exit(1);
}
$_error_msgs = [];
$ok = true;
include $_cur_test_file;
foreach (file($_cur_test_file) as $_cur_test_file_line_no => $_cur_test_file_line) {
if (preg_match('/^\s*function\s+(test_.+?)\s*\(/', $_cur_test_file_line, $m)) {
$_cur_test_func = $m[1];
$_assert_count[$_cur_test_func] = 0;
$_assert_count_fail[$_cur_test_func] = 0;
$_cur_test_func();
$total = $_assert_count[$_cur_test_func];
$fail = $_assert_count_fail[$_cur_test_func];
$ok = $total - $fail;
echo "=== ",("$_cur_test_func ($ok/$total)")," ===\n";
if ($ok !== $total) $ok = false;
if ($fail) foreach ($_error_msgs[$_cur_test_func] as $msg) echo "$msg\n";
}
}
if ($ok) echo "OK.\n";
else {
echo "Bomb!!! Failed.";
exit(1);
}
// === lib ===
function http($line, $headers, $body = null)
{
$a = explode(" ", $line);
$ch = curl_init();
if (count($a) == 2) {
list($method, $url) = $a;
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
} else {
$url = $a;
}
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_TIMEOUT,2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_HEADER, 1);
if ($body !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); // windows
echo "$line ",json_encode($headers)," $body\n";
$ret = curl_exec($ch);
assert_equal(curl_errno($ch), 0);
assert_equal(curl_error($ch), "");
$info = curl_getinfo($ch);
curl_close($ch);
$header_size = $info['header_size'];
return [$info, substr($ret, 0, $header_size), substr($ret, $header_size)];
}
function http_json($line, $headers, $body = null)
{
list($info, $_, $ret) = http($line, $headers, $body);
assert_equal($info['http_code'], 200);
$j = json_decode($ret, true);
assert_equal(json_last_error(), JSON_ERROR_NONE);
return $j;
}
function assert_type($type, $value)
{
$_cur_test_func = $GLOBALS['_cur_test_func'];
$GLOBALS['_assert_count'][$_cur_test_func]++;
$func = "is_$type";
$b = $func($value);
if (!$b) {
$GLOBALS['_assert_count_fail'][$_cur_test_func]++;
$GLOBALS['_error_msgs'][$_cur_test_func][] = _get_error_msg_with_func_info("real type is ".gettype($type));
}
}
function assert_equal($value, $should)
{
$_cur_test_func = $GLOBALS['_cur_test_func'];
$GLOBALS['_assert_count'][$_cur_test_func]++;
if ($value !== $should) {
$GLOBALS['_assert_count_fail'][$_cur_test_func]++;
$GLOBALS['_error_msgs'][$_cur_test_func][] = _get_error_msg_with_func_info("value is ".json_encode($value));
}
}
function assert_array_key($arr, $key)
{
$_cur_test_func = $GLOBALS['_cur_test_func'];
$GLOBALS['_assert_count'][$_cur_test_func]++;
if (!isset($arr[$key])) {
$GLOBALS['_assert_count_fail'][$_cur_test_func]++;
$GLOBALS['_error_msgs'][$_cur_test_func][] = _get_error_msg_with_func_info("array no key $key");
}
}
function assert_table($table, $titles, $should_table)
{
$_cur_test_func = $GLOBALS['_cur_test_func'];
$GLOBALS['_assert_count'][$_cur_test_func]++;
if (!is_array($table)) {
$GLOBALS['_assert_count_fail'][$_cur_test_func]++;
$GLOBALS['_error_msgs'][$_cur_test_func][] = _get_error_msg_with_func_info("not array");
return;
}
foreach ($table as $index => $row) {
foreach ($titles as $title) {
if (!isset($row[$title])) {
$GLOBALS['_assert_count_fail'][$_cur_test_func]++;
$GLOBALS['_error_msgs'][$_cur_test_func][] = _get_error_msg_with_func_info("index $index: [".json_encode($row)."] has no title $title");
return;
}
}
}
foreach ($should_table as $should_row) {
$found = false;
foreach ($table as $row) {
if (_row_equal($row, $should_row, $titles)) $found = true;
}
if (!$found) {
$GLOBALS['_assert_count_fail'][$_cur_test_func]++;
$GLOBALS['_error_msgs'][$_cur_test_func][] = _get_error_msg_with_func_info("index $index has no row ".json_encode($should_row));
return;
}
}
}
function _row_equal($row, $should_row, $titles) {
$i = 0;
foreach ($titles as $title) {
if (!(isset($row[$title]) &&
$should_row[$i++]
===
$row[$title]))
return false;
}
return true;
}
function _get_error_msg_with_func_info($msg)
{
$start_push = false;
$trace = [];
foreach (debug_backtrace() as $dbt) {
$function = $dbt['function'];
if (strpos($function, 'assert_') === 0) {
$start_push = true;
}
if (strpos($function, 'test_') === 0) {
$start_push = false;
break;
}
if ($start_push)
$trace[] = $dbt;
}
$msgs = ["$msg\n"];
foreach ($trace as $i=> $t) {
$msgs[] = "\t[$i] $t[file]:$t[line] "._get_line_content($t['file'], $t['line'])."\n";
}
return implode("", $msgs);
}
function _get_line_content($file, $line) {
return trim(file($file)[$line-1]);
}
@picasso250
Copy link
Author

新建一个文件 如 test_for_last_month_work.php

<?php

function test_xxx()
{
    $url = 'test';
    $postData = [
        "id" => "xx",
    ];
    $data = _do_post($url, $postData);
    assert_table(
        $data,
        ['title1', 'name', 'title2'],
        [
            ['61', 'xc', '2018-03-21 11:16:23'],
            ['2', 'wc', '2018-02-07 15:28:33']
        ]
    );
}

function _do_post($url, $postData)
{
    $url = "https://myhost/$url";
    $ret = http_json("POST $url", [], json_encode($postData));
    assert_type('array', $ret);
    assert_array_key($ret, 'code');
    assert_array_key($ret, 'data');
    assert_equal($ret['code'], 0);
    assert_type('array', $ret['data']);
    return $ret['data'];
}

然后运行

php behav-test.php test_for_last_month_work.php

会自动提取此文件中所有 test_.* 函数,然后执行

输出

=== test_xxx (10/10) ===
OK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment