Phpunit密码比较

时间:2013-05-30 22:16:23

标签: database testing passwords comparison phpunit

我想测试其中一个开发人员生成的登录功能。我想要做的是在我的setUp中创建测试用户,然后我想使用这些用户来测试登录功能。我想看到当用户名和密码等于我们数据库中存储的用户名和密码时,它会返回正确的布尔值。我的问题是,当我插入我的用户时,我正在以纯文本形式提供密码,因此它们以纯文本形式存储在数据库中,但是这里存在问题。当您尝试登录时,登录功能会对密码进行哈希处理,因为注册完成后会对数据库中的密码进行哈希处理。所以基本上我刚刚插入的纯文本密码将永远不会匹配,因为登录功能会在查找匹配项时对密码进行哈希处理。所以我需要做的是在插入测试用户密码时对其进行哈希处理。我该怎么做呢?这就是我的代码目前的样子:

<?php

include 'functions.php';


class Test extends PHPUnit_Framework_TestCase {


protected function setUp(){

global $mysqli;
$mysqli = new mysqli('localhost', 'xxx', 'xxxxx', 'xxxxx');


$mysqli->query("INSERT INTO members (id, username, pnumber, password) VALUES  ('200',        'testbrute', '920314', 'xxxxx')");


}


public function testLogin(){

global $mysqli;

    $correctPass = Login('920314','xxxxxx', $mysqli);
    $this->assertTrue($correctPass);


    $wrongPass = Login('920314','xxxxxxxxx', $mysqli);
    $this->assertFalse($wrongPass);


$NoUserExists = Login("980611-5298","--..--..--", $mysqli);
$this->assertFalse($NoUserExists);

}


protected function tearDown(){
$mysqli = new mysqli('localhost', 'xxx', 'xxxxx', 'xxxxx'); 



$mysqli->query("DELETE FROM members WHERE id IN (200)");


}

}
?>

这是登录功能的样子:

function login($pnumber, $password, $mysqli) {
 // Using prepared Statements means that SQL injection is not possible. 
 if ($stmt = $mysqli->prepare("SELECT id, username, password, salt FROM members WHERE     pnumber = ? LIMIT 1")) { 
  $stmt->bind_param('s', $pnumber); // Bind "$pnumber" to parameter.
  $stmt->execute(); // Execute the prepared query.
  $stmt->store_result();
  $stmt->bind_result($user_id, $username, $db_password, $salt); // get variables from  result.
  $stmt->fetch();
  $password = hash('sha512', $password.$salt); // hash the password with the unique salt.

  if($stmt->num_rows == 1) { // If the user exists
     // We check if the account is locked from too many login attempts
     if(checkbrute($user_id, $mysqli) == true) { 
        // Account is locked
        // Send an email to user saying their account is locked
        return "account locked";
     } else {
     if($db_password == $password) { // Check if the password in the database matches the password the user submitted. 
        // Password is correct!

           $ip_address = $_SERVER['REMOTE_ADDR']; // Get the IP address of the user. 
           $user_browser = $_SERVER['HTTP_USER_AGENT']; // Get the user-agent string of the user.

           $user_id = preg_replace("/[^0-9]+/", "", $user_id); // XSS protection as we     might print this value
           $_SESSION['user_id'] = $user_id; 
           $username = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $username); // XSS     protection as we might print this value
           $_SESSION['username'] = $username;
           $_SESSION['login_string'] = hash('sha512',        $password.$ip_address.$user_browser);
           // Login successful.
           return "login successful";    
     } else {
        // Password is not correct
        // We record this attempt in the database
        $now = time();
        $mysqli->query("INSERT INTO login_attempts (user_id, time) VALUES ('$user_id',  '$now')");
        return 'pass incorrect';
     }
  }
  } else {
     // No user exists. 
     return 'no exist';
      }
   }
}

我是phpunit的新手,一般都是测试,所以请过于描述。

1 个答案:

答案 0 :(得分:0)

忘记尝试针对实际数据库进行测试。作为一般规则,如果您可以提供帮助,则不希望您的测试依赖于外部服务。

您可以注入模拟mysqli对象并指定它的行为。然后,您不必担心任何值被添加到数据库或依赖于数据库甚至存在。

所以在你的测试中,而不是声明global $mysqli做:

$mockMysqli = $this->getMockBuilder('mysqli')
                   ->disableOriginalConstructor()
                   ->setMethods(array('prepare'))
                   ->getMock();

$mockMysqli->expects($this->once())
           ->method('prepare')
           ->will($this->returnValue($mockStmt) //Have to also create a mock mysqli_stmt object

根据你的函数的方式,你最终会得到一些模拟对象返回其他模拟对象,这是你运行的代码气味太多了。因此,您最好将其分解成更小的部分,然后可以单独进行模拟和测试。我发现,一般来说,如果功能很难测试,它不是一个好的设计,应该重构。大多数好的设计最终都很容易用一个或两个模拟对象进行测试。