因此, strlen() 不合作。
如果某些代码不合作,我会执行以下操作:
- 隔离问题。通过摆脱一切不相关的东西。
- 试着通过问自己“我的主张和期望是什么?”来澄清它应该做什么。
- 编写一个特定的脚本来测试行为不端的代码
- 修改行为不端的代码,直到它的行为符合预期(如果需要,使其更易于测试)。
隔离问题。通过摆脱一切不相关的东西。
首先,让我们使用您的原始示例代码并摆脱与手头特定问题无关的所有内容。只留下使用 strlen 的验证代码。所以,我们现在可以看得更清楚了。
然后,尝试通过询问“我的主张和期望是什么?”来澄清它应该做什么。
我从你的代码中猜想:
- 给定
- 信息字段(标题、姓名、IP )
- 及其最小长度
- 及其最大长度
- 当用户提交的值小于最小长度或大于最大长度时
- 否则没关系
编写一个特定的脚本来测试行为不端的代码
我会创建一个 html/php 脚本,纯粹是为了测试导致悲伤的 php。举个FormFieldValidatorTest.php
例子。测试脚本位于网站项目中,但仅供我运行。因此,我会将其放入受密码保护的目录或其他公众无法访问的地方。
我想要一个提交一些已知长度字符串的UTF-8 html 页面。比如说,我们知道的字母“a”是一个字符长,而一个“空字段”我们知道是零个字符长。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>My Test</title>
</head>
<body>
<form action="" method="get">
<input name="singleCharacterString" type="text" value="a" size="1" maxlength="1">
<input name="emptyString" type="text" value="" size="1" >
<input type="submit" name="Submit" value="Run Tests">
</form>
...
然后,在顶部FormFieldValidatorTest.php
我会写一些 php 代码:
- 接收那些固定的、硬编码的表单值(夹具数据)。
- 将夹具数据传递给一些测试,然后
- 给我返回一系列结果
为了保持干净,我将测试代码的核心内容放入一个函数中,调用它 runTestSuite()
,下面将对其进行充实。
<?php
//FormFieldValidatorTest.php
if ( $_REQUEST['Submit'] == 'Run Tests' ) {
//perform the tests
$testResultsArray = runTestSuite();
/**
* Lets loop through the results and count the failures
*/
$failureCounter = 0;
foreach ( $testResultsArray as $result ) {
if ( $result['hasFailed'] ) {
$failureCounter++;
}
}
} else {
//no tests were run set the results to null
$testResultsArray = null;
}
?>
<html>
...
我会在 .html 的 html 部分中添加一些 php FormFieldValidatorTest.php
。如果它们被运行,这应该打印出结果(即当$testResultsArray
与 不同时null
):
<?php
//FormFieldValidatorTest.php
...
?>
<html>
...
<body>
<form action="" method="get">
...
</form>
<?php if ( $testResultsArray !== null ) : ?>
<h1>Results</h1>
<pre>
<?php if ( $failureCounter > 0 ) : ?>
Failed. <?php echo $failureCounter ?> tests failed.
<?php print_r( $testResultsArray ); ?>
<?php else : ?>
Passed
<?php endif; ?>
</pre>
<?php endif; ?>
</body>
</html>
然后,我会填写我的runTestSuite()
功能的胆量。这基本上是对assertTrue()
我稍后充实的函数的两次调用。
- 首先,它断言 strlen
1
在给定singleCharacterString
.
- 然后,它断言 strlen
0
在给定emptyString
.
同时它传递一条描述每个测试的消息。这些存储在结果数组中,以在测试失败时帮助调试。
/**
* @desc A suite of tests to excercise that troublesome code
* @return array of results for each test done
*/
function runTestSuite() {
/**
* Lets Run some tests
*/
/**
* Create the results array
*/
$testResultsArray = array();
/**
* Test some known data submitted via a form parameter
*/
assertTrue(
( strlen( $_REQUEST['singleCharacterString'] ) == 1 ),
'Expect it to be TRUE that singleCharacterString http parameter
has a stringlength of 1',
$testResultsArray );
/**
* @todo Add more tests here.
*/
assertTrue(
( strlen( $_REQUEST['emptyString'] ) == 0 ),
'Expect it to be TRUE that emptyString http parameter
has a stringlength of 0',
$testResultsArray );
return $testResultsArray;
}
最后,我充实了这个assertTrue()
功能。这基本上测试第一个参数是否未通过断言测试。然后,它将该结果和message
作为记录附加到$testResultsArray
.
/**
* @desc A TRUE assertion
* @param mixed - a value that we expect to be true
* @param string - a message to help understand what we are testing
* @param array - a collection of results so far passed by reference
* @return void
*/
function assertTrue( $value, $message, &$testResultsArray ) {
if ( $value ) {
//value is as asserted
$currentResult = array(
'message' => $message,
'hasFailed' => FALSE
);
} else {
//value is not as asserted
$currentResult = array(
'message' => $message,
'hasFailed' => TRUE
);
}
$testResultsArray[] = $currentResult;
}
现在测试脚本完成了。在这里看到它。
如果我运行它并看到它通过,我可以确定 strlen 正在合作。如果它失败了,我可以继续:
修改行为不端的代码,直到其行为符合预期。
为了做到这一点,您可能需要能够将行为不端的位拆分为位于其自己文件中的单独函数或类。这使其可重用,因此可以从测试代码和实时生产代码中调用它。
我们真正应该测试的是长度规则,它指定只允许特定长度的字符串。
所以,让我们隔离它,以便我们可以测试它。也许规则库中的一个函数称为 isCorrectLength() 在一个名为的文件中ServerValidationRules.php
<?php
//ServerValidationRules.php
/**
* @desc boolean function to test string length
* @param string to test
* @param integer defining minimum length required
* @param integer defining maximum length required
* @return TRUE if its the correct length, FALSE otherwise.
*/
function isCorrectLength( $string, $minLength, $maxLength ) {
if ( strlen( $string ) < $minLength ) {
//its too short
return FALSE;
}
if ( strlen( $string ) > $maxLength ) {
//its too long
return FALSE;
}
return TRUE;
}
然后我们可以替换测试中的代码以使用它而不是本机strlen()
函数。
<?php
//FormFieldValidatorTest.php
require_once('ServerValidationRules.php');
...
/**
* @desc A suite of tests to excercise that troublesome code
* @return array of results for each test done
*/
function runTestSuite() {
$testResultsArray = array();
/**
* Test some known data submitted via a form parameter
*/
assertTrue(
//( strlen( $_REQUEST['singleCharacterString'] ) == 1 ),
isCorrectLength( $_REQUEST['singleCharacterString'], 0, 1 ),
'Expect it to be TRUE that singleCharacterString http parameter
has a stringlength of 1',
$testResultsArray );
/**
* @todo Add more tests here.
*/
assertTrue(
//( strlen( $_REQUEST['emptyString'] ) == 0 ),
isCorrectLength( $_REQUEST['emptyString'], 0, 0 ),
'Expect it to be TRUE that emptyString http parameter
has a stringlength of 0',
$testResultsArray );
return $testResultsArray;
}
...
因此,我们现在可以将生产脚本中的代码替换为:
<title>Terraria Server List</title>
...
<?php
...
if ( $submit ) {
if (!( isCorrectLength( $title, 0, 50 ) )) {
die("Invalid title!");
}
elseif (!( isCorrectLength($ip, 0, 50) )) {
die("Invalid IP!");
}
elseif (!( isCorrectLength( $desc, 0, 10000 ) )) {
die("Invalid description!");
}
elseif (!( isCorrectLength( $email, 0, 100 ) )) {
die("Invalid E-Mail!");
}
else {
//do the insert
}
}
...
或者,更好的是,将长度规则移动到单个函数中,以便逻辑可以被其他代码(即测试套件中的某些代码)重用。
我们可以将所有这些包装成一个名为的函数isServerFieldsValid
并将其放入我们的ServerValidationRules.php
文件中。
<?php
//ServerValidationRules.php
...
/**
* @desc tests user-submitted fields appending feedback to an array of messages upon failure.
* @param associative array of Posted values keyed by field name
* @param array of messages passed by reference
* @return boolean True if all fields are valid. False otherwise.
*/
function isServerFieldsValid( $values, &$messages ) {
$hasFailed = FALSE;
if (!( isCorrectLength( $values['title'], 1, 50 ) )) {
$hasFailed = TRUE;
$messages[] = "Invalid title!";
}
if (!( isCorrectLength($values['ip'], 1, 50) )) {
$hasFailed = TRUE;
$messages[] = "Invalid IP!";
}
if (!( isCorrectLength( $values['desc'], 1, 1000 ) )) {
$hasFailed = TRUE;
$messages[] = "Invalid description!";
}
if (!( isCorrectLength( $values['email'], 1, 100 ) )) {
$hasFailed = TRUE;
$messages[] = "Invalid E-Mail!";
}
if ( $hasFailed ) {
return FALSE;
}
//else
return TRUE;
}
然后在我们的测试脚本中为测试套件函数添加一些更多的断言。
...
/**
* @desc A suite of tests to excercise that troublesome code
* @return array of results for each test done
*/
function runTestSuite() {
/**
* Initialize the results array
*/
$testResultsArray = array();
...
/**
* Test some variants of possible user submitted data
*
* @todo We ought to invoke an assertFalse() function.
* In meantime, hack it by passing a negated value to assertTrue().
*/
/**
* When given values that are too long,
* expect a validation failure.
*/
$validationMessages = array();
$result = isServerFieldsValid(
array(
'title' => str_repeat( 'a' , 51 ),
'ip' => str_repeat( 'a' , 51 ),
'desc' => str_repeat( 'a' , 1001 ),
//?'type' => str_repeat( 'a' , 1001 ),
'email' => str_repeat( 'a' , 101 ),
),
$validationMessages
);
assertTrue(
(!( $result )),
'Expect it to be TRUE that result is False when given long values',
$testResultsArray );
assertTrue(
in_array( 'Invalid title!', $validationMessages ),
'Expect messages to say "Invalid title!"',
$testResultsArray );
assertTrue(
in_array( 'Invalid IP!', $validationMessages ),
'Expect messages to say "Invalid IP!"',
$testResultsArray );
assertTrue(
in_array( 'Invalid description!', $validationMessages ),
'Expect messages to say "Invalid description!"',
$testResultsArray );
assertTrue(
in_array( 'Invalid E-Mail!', $validationMessages ),
'Expect messages to say "Invalid E-Mail!"',
$testResultsArray );
/**
* When given values that are too short,
* expect a validation failure.
*/
$validationMessages = array();
$result = isServerFieldsValid(
array(
'title' => null,
'ip' => null,
'desc' => null,
'email' => null,
),
$validationMessages
);
assertTrue(
(!( $result )),
'Expect it to be TRUE that result is False when given short values',
$testResultsArray );
assertTrue(
in_array( 'Invalid title!', $validationMessages ),
'Expect messages to say "Invalid title!"',
$testResultsArray );
assertTrue(
in_array( 'Invalid IP!', $validationMessages ),
'Expect messages to say "Invalid IP!"',
$testResultsArray );
assertTrue(
in_array( 'Invalid description!', $validationMessages ),
'Expect messages to say "Invalid description!"',
$testResultsArray );
assertTrue(
in_array( 'Invalid E-Mail!', $validationMessages ),
'Expect messages to say "Invalid E-Mail!"',
$testResultsArray );
/**
* When given values that are the correct length,
* expect a validation success.
*/
$validationMessages = array();
$result = isServerFieldsValid(
array(
'title' => 'a title',
'ip' => 'an ip',
'desc' => 'a desc',
'email' => 'an email',
),
$validationMessages
);
assertTrue(
( $result ),
'Expect it to be TRUE that result is True when given correct values',
$testResultsArray );
assertTrue(
(!( in_array( 'Invalid title!', $validationMessages ) )),
'Expect messages NOT to say "Invalid title!"',
$testResultsArray );
assertTrue(
(!( in_array( 'Invalid IP!', $validationMessages ) )),
'Expect messages NOT to say "Invalid IP!"',
$testResultsArray );
assertTrue(
(!( in_array( 'Invalid description!', $validationMessages ) )),
'Expect messages NOT to say "Invalid description!"',
$testResultsArray );
assertTrue(
(!( in_array( 'Invalid E-Mail!', $validationMessages ) )),
'Expect messages NOT to say "Invalid E-Mail!"',
$testResultsArray );
return $testResultsArray;
}
...
所以,完整的测试脚本现在看起来像这样。
if (strlen ) { die }
因此,如果通过了,我们可以通过调用新的、经过良好测试的isServerFieldsValid()
函数替换所有这些语句来修改生产代码:
<title>Terraria Server List</title>
...
if ( $submit ) {
$messages = array();
if (!( isServerFieldsValid( $_POST, $messages ) )) {
echo 'Invalid data was submitted:' . PHP_EOL;
foreach( $messages as $message ) {
echo $message . PHP_EOL;
}
exit;
} else {
//do the insert
}
...
好吧,这就是我处理无论如何不合作的代码的方式。
编码 :
笔记:
我花了几个小时来写这个答案,但写实际测试的时间却很少。一旦你养成了习惯,通常只需要几分钟就可以草草写出一个测试并找出为什么某些代码不合作。
提示:您不需要编写自己的断言函数。见:http ://www.simpletest.org/en/start-testing.html