上記の回答のほとんどは、乱数ジェネレーターをモックすることが道であると示していますが、組み込みのmt_rand関数を単に使用していました。モックを許可することは、クラスを書き換えて、構築時に乱数ジェネレーターを挿入することを要求することを意味します。
かと思った!
名前空間の追加の結果の1つは、PHP関数に組み込まれたモックが信じられないほど難しいものから簡単なものになったことです。SUTが指定された名前空間にある場合、その名前空間の単体テストで独自のmt_rand関数を定義するだけで、テスト期間中は組み込みのPHP関数の代わりに使用されます。
これが最終的なテストスイートです。
namespace gordian\reefknot\util;
/**
* The following function will take the place of mt_rand for the duration of
* the test. It always returns the number exactly half way between the min
* and the max.
*/
function mt_rand ($min = 42, $max = NULL)
{
$min = intval ($min);
$max = intval ($max);
$max = $max < $min? $min: $max;
$ret = round (($max - $min) / 2) + $min;
//fwrite (STDOUT, PHP_EOL . PHP_EOL . $ret . PHP_EOL . PHP_EOL);
return ($ret);
}
/**
* Override the password character pool for the test
*/
class PasswordSubclass extends Password
{
const CHARLIST = 'AAAAAAAAAA';
}
/**
* Test class for Password.
* Generated by PHPUnit on 2011-12-17 at 18:10:33.
*/
class PasswordTest extends \PHPUnit_Framework_TestCase
{
/**
* @var gordian\reefknot\util\Password
*/
protected $object;
const PWMIN = 15;
const PWMAX = 20;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp ()
{
}
/**
* Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed.
*/
protected function tearDown ()
{
}
public function testGetPassword ()
{
$this -> object = new PasswordSubclass (self::PWMIN, self::PWMAX);
$pw = $this -> object -> getPassword ();
$this -> assertTrue ((bool) preg_match ('/^A{' . self::PWMIN . ',' . self::PWMAX . '}$/', $pw));
$this -> assertTrue (strlen ($pw) >= self::PWMIN);
$this -> assertTrue (strlen ($pw) <= self::PWMAX);
$this -> assertTrue ($pw === $this -> object -> getPassword ());
}
public function testGetPasswordFixedLen ()
{
$this -> object = new PasswordSubclass (self::PWMIN, self::PWMIN);
$pw = $this -> object -> getPassword ();
$this -> assertTrue ($pw === 'AAAAAAAAAAAAAAA');
$this -> assertTrue ($pw === $this -> object -> getPassword ());
}
public function testGetPasswordFixedLen2 ()
{
$this -> object = new PasswordSubclass (self::PWMAX, self::PWMAX);
$pw = $this -> object -> getPassword ();
$this -> assertTrue ($pw === 'AAAAAAAAAAAAAAAAAAAA');
$this -> assertTrue ($pw === $this -> object -> getPassword ());
}
public function testInvalidLenThrowsException ()
{
$exception = NULL;
try
{
$this -> object = new PasswordSubclass (self::PWMAX, self::PWMIN);
}
catch (\Exception $e)
{
$exception = $e;
}
$this -> assertTrue ($exception instanceof \InvalidArgumentException);
}
}
PHP内部関数をオーバーライドすることは、私にはまったく発生していなかった名前空間のもう1つの用途であるため、これについて言及したいと思いました。これを助けてくれたみんなに感謝します。