在PHPUnit中的内存中SQLITE数据库中模拟数据

时间:2017-06-20 08:04:22

标签: php sqlite phpunit dbunit

我目前正在学习如何在PHPUnit框架中测试数据库,并在我的测试中遇到了我不想连接到真实数据库的问题。这是因为当我在另一台计算机上运行测试时,这台计算机可能没有相同的数据库。

我实现了\PHPUnit\DbUnit\TestCaseTrait特征并设置了以下方法:

/**
 * Returns the test database connection.
 *
 * @return \PHPUnit\DbUnit\Database\Connection
 */
protected function getConnection()
{
    $pdo = new PDO('sqlite::memory:');
    return $this->createDefaultDBConnection($pdo, ':memory:');
}

/**
 * Returns the test dataset.
 *
 * @return \PHPUnit\DbUnit\DataSet\IDataSet
 */
protected function getDataSet()
{
    return $this->createXMLDataSet(dirname(__FILE__) . '/test-dataset.xml');
}

数据集文件存在,并且找到正确。

在我测试的setUp方法中,我将对象中的变量设置为\PDO实例。

/**
 * @var PDO $databaseServerConnection
 */
private $databaseServerConnection;

public function setUp()
{
    $this->databaseServerConnection = $this->getConnection()->getConnection();
}

我希望我现在可以将{PDO}与来自getDataSet()方法中的数据集文件的数据一起使用。

对于我自己的尝试,我尝试使用以下代码进行比较:

# Specify the tables we want to have in our connection dataset
$tables = ['users'];

# Create the dataset in the connection with the tables
$dataset = $this->getConnection()->createDataSet($tables);

# Query all results from the user table  in the connection
$queryTable = $this->getConnection()->createQueryTable(
    'users', 'SELECT * FROM users'
);

# Get the raw table data from the dataset file
$expectedTable = $this->getDataSet()->getTable('users');

# Check if theyre equal
$this->assertTablesEqual($queryTable, $expectedTable);

调试时,我注意到$tables中的$dataset数组变量只是一个空的。这是var_dump变量的$dataset

class PHPUnit\DbUnit\Database\FilteredDataSet#18 (3) {
  protected $tableNames =>
  array(1) {
    [0] =>
    string(5) "users"
  }
  protected $tables =>
  array(0) {
  }
  protected $databaseConnection =>
  class PHPUnit\DbUnit\Database\DefaultConnection#16 (2) {
    protected $connection =>
    class PDO#15 (0) {
    }
    protected $metaData =>
    class PHPUnit\DbUnit\Database\Metadata\Sqlite#17 (6) {
      protected $columns =>
      array(0) {
        ...
      }
      protected $keys =>
      array(0) {
        ...
      }
      protected $truncateCommand =>
      string(11) "DELETE FROM"
      protected $pdo =>
      class PDO#15 (0) {
        ...
      }
      protected $schema =>
      string(8) ":memory:"
      protected $schemaObjectQuoteChar =>
      string(1) """
    }
  }
}

$data变量中的$queryTable数组也是null。这是var_dump变量的$queryTable

class PHPUnit\DbUnit\DataSet\QueryTable#22 (6) {
  protected $query =>
  string(19) "SELECT * FROM users"
  protected $databaseConnection =>
  class PHPUnit\DbUnit\Database\DefaultConnection#20 (2) {
    protected $connection =>
    class PDO#19 (0) {
    }
    protected $metaData =>
    class PHPUnit\DbUnit\Database\Metadata\Sqlite#21 (6) {
      protected $columns =>
      array(0) {
        ...
      }
      protected $keys =>
      array(0) {
        ...
      }
      protected $truncateCommand =>
      string(11) "DELETE FROM"
      protected $pdo =>
      class PDO#19 (0) {
        ...
      }
      protected $schema =>
      string(8) ":memory:"
      protected $schemaObjectQuoteChar =>
      string(1) """
    }
  }
  protected $tableName =>
  string(5) "users"
  protected $tableMetaData =>
  NULL
  protected $data =>
  NULL
  private $other =>
  NULL
}

$data变量中的$expectedTable数组充满了数据集文件中创建的数据时。

class PHPUnit\DbUnit\DataSet\DefaultTable#30 (3) {
  protected $tableMetaData =>
  class PHPUnit\DbUnit\DataSet\DefaultTableMetadata#34 (3) {
    protected $columns =>
    array(3) {
      [0] =>
      string(2) "id"
      [1] =>
      string(4) "name"
      [2] =>
      string(5) "email"
    }
    protected $primaryKeys =>
    array(0) {
    }
    protected $tableName =>
    string(5) "users"
  }
  protected $data =>
  array(4) {
    [0] =>
    array(3) {
      'id' =>
      string(1) "1"
      'name' =>
      string(3) "test1"
      'email' =>
      string(9) "test1@me.nl"
    }
    [1] =>
    array(3) {
      'id' =>
      string(1) "2"
      'name' =>
      string(3) "test2"
      'email' =>
      string(9) "test2@me.nl"
    }
    [2] =>
    array(3) {
      'id' =>
      string(1) "3"
      'name' =>
      string(6) "test3"
      'email' =>
      string(12) "test3@me.nl"
    }
    [3] =>
    array(3) {
      'id' =>
      string(1) "4"
      'name' =>
      string(4) "test4"
      'email' =>
      string(10) "test4@me.nl"
    }
  }
  private $other =>
  NULL
}

我还尝试在getConnection()方法内的pdo连接对象上执行2个查询,以创建包含其中值的表:

protected function getConnection()
{
    $pdo = new PDO('sqlite::memory:');
    $pdo->exec("CREATE TABLE users (id PRIMARY KEY, name VARCHAR(50), email VARCHAR(50))");
    $pdo->exec("INSERT INTO users (id, name, email) VALUES (20, 'Bas', 'aa@me')");

    return $this->createDefaultDBConnection($pdo, ':memory:');
}

我的连接中没有任何可用数据,如何将数据集文件中的数据导入到此处以使测试通过?

此外,这是一个很好的做法吗?

2 个答案:

答案 0 :(得分:4)

据我所知,您在{1}}中覆盖setUp()的{​​{1}},其中包含负责setting up and tearing down的逻辑。

如果你需要在TestCases中使用不同的\PHPUnit\DbUnit\TestCaseTrait,那么最好在docs中创建自己的基类described并从中扩展你的TestCase,并调用setUp()来自儿童TestCase

<强>更新

  

必须创建数据库,表,序列,触发器和视图   在运行测试套件之前。

取自here,并且有更多有用的提示。

基本上,这意味着在运行测试之前,所有表,列,索引,约束以及测试中与db相关的代码所处理和依赖的其他内容都应该到位。运行前该数据库中的任何内容都无关紧要,TestCase数据集中的所有表都将被截断并填充该数据集中的数据。

更新2: (免责声明:以下是我个人的偏好)

通常通过某种网关实现对db的访问。它们是我实施的最后一件事(至少在封装范围内)。这让我有机会在我开始做这些网关时真正了解需要存储在数据库中的数据。因此,当开始在某个网关上编写一些TestCase时,我只需要使用管理工具(通常是一些GUI,如phpMyAdmin)和创建表(表)以及我认为需要存在的列来存储网关处理的数据。然后编写测试并运行它们可能会在更改表格之间进行更好的匹配。

使用这种方法,db的所有结构都是手动创建的(而不是通过测试代码),并且它与在db上运行的代码一起增长。我发现它很方便,有几个原因。

首先,这是更简单的,因为我不必在每个TestCase之前管理创建(或重新创建)结构。特别是如果我有几个可以使用相同表格的TestCase。

其次,我总是有db结构,适合传递测试。任何不合适的结构变化都会被捕获。此外,我总是可以为这个正确的结构生成一个sql导出指令,以启动具有所有需要的表,列,索引,键等的真实数据库。

第三,有时需要(甚至必须)对数据库采取仅考虑特定于数据库的问题。因此,我总是可以打开当前的测试数据库,并清楚地看到它是由什么组成的。

关于内存数据库的注意事项。 在这种情况下,需要在代码中创建结构。这里可能有两个显而易见的选项 - 为整个测试套件或特定测试用例(或其中的一组)设置具有特定结构的数据库。至于我,我会根据上述原因做第一个。

最简单的实现方法是在bootrstrap文件中建立连接并创建结构。但是我会投入一些时间并添加一些这样的动态:

setUp

parent::setUp()

这会使测试与环境约束更加分离 - 只需要配置调整来运行测试。实际上我会做更多,并使用带有sql语句的文件来加载<?xml version="1.0" encoding="UTF-8" ?> <phpunit> <php> <var name="MAKE_IN_MEMORY_DB" value="yes" /> </php> </phpunit> 内的文件(需要一些额外的工作,但我认为这是值得的。)

答案 1 :(得分:0)

没有人死灵,但我发现这很有帮助;

// phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
 <phpunit backupGlobals="false"
  <php>
    <server name="APP_ENV" value="testing"/>
    <server name="SESSION_DRIVER" value="array"/>
    <server name="DB_CONNECTION" value="sqlite"/>
    <server name="DB_DATABASE" value=":memory:"/>
  </php>
 </phpunit>