如果使用 ORM 层,如何在 PHP 中进行单元测试?

发布于 2024-10-29 22:11:54 字数 380 浏览 5 评论 0原文

我有一堂课,比如说“人”。 ORM层根据sql结构生成了相应的对象。 person 类有一个方法:Get($id)。在 Get 方法中,调用对象 Person 并检索表中的字段。

我基本上想做以下单元测试:创建一个新人并检查 Get 方法是否返回正确的信息。

  • 在这种情况下单元测试应该如何工作?
  • 我是否需要创建一个单独的数据库(仅结构),并从该数据库进行创建/选择?
  • boostrap 文件是否应该加载与我正在使用的框架相同的配置,但更改配置文件以便它可以与假数据库一起使用?
  • 我应该在每次测试后清理新数据库吗?

    在看到您的回复后,我也在想,在不实际构建新数据库的情况下模拟 ORM 响应是否不是正确的方法?

  • I have a class let's say Person. The ORM layer has generated based on the sql structure the corresponding objects. The class person has a method: Get($id). In the Get method, the object Person is called and the field from the table are retrieved.

    I basically want to make the following unit test: create a new person and check if the Get method is returning the right information.

  • How is the unit testing supposed to work in this condition ?
  • Do I need to create a separate database ( just the structure ), and make the creation/selection from that database?
  • Should the boostrap file load the same configuration as the framework I'm using but change the configuration file so It works with the fake database ?
  • Should I clean the new database each after each test ?

    I was also wandering after seeing your responses if simulating an ORM response without actually building a new database is not the way to go ?

  • 如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

    扫码二维码加入Web技术交流群

    发布评论

    需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

    评论(3

    独守阴晴ぅ圆缺 2024-11-05 22:11:54

    在这种情况下单元测试应该如何工作?

    一般来说,您应该在心理上将单元测试分为两部分:

    • 代码的一部分可以在没有数据库的情况下进行测试,因此您可以存根或模拟访问数据库的方法,
    • 测试的另一部分需要使用数据库,因为它测试 ORM 是否使用正确。

    我需要创建一个单独的数据库吗?

    这取决于您的需求。 Rails 应用程序通常具有测试/开发/生产“环境” - 数据库、配置、存储目录。
    测试用于运行单元测试,开发用于开发事物,生产用于运行实时服务器。在开发过程中,您将针对开发配置以及开发数据库运行。对于单元测试,使用测试环境,其优点是数据库中的用户不会被删除或破坏。

    我喜欢这个概念;在我的 phpunit 测试中,我经常在引导程序中有一个开关来更改加载的配置文件。请记住,您的开发数据库通常包含比单个单元测试所需的数据更多的数据,并且您可能手工制作这些数据并且不想丢失。此外,另一个数据库不需要花钱。

    每次测试后我应该清理新数据库吗?

    我主要只清理将在测试中使用的桌子。清理数据库可确保您不会因之前的测试而产生副作用。

    How is the unit testing supposed to work in this condition ?

    Generally, you should split your unittests mentally in two parts:

    • one part of your code is testable without the database, so you can stub or mock the methods that do the database access
    • the other part of your tests needs to work with the database, since it tests if the ORM is used correctly.

    Do I need to create a separate database

    This depends on your needs. Rails apps generally have testing/development/production "environments" - database, configuration, storage directories.
    Testing is for running unit tests, dev for developing things and production for running the live server. While developing, you run against the dev configuration and thus your development database. For unit tests, the testing env is used which has the benefit that i.e. users in the database are not deleted or broken.

    I like that concept; in my phpunit tests I often do have a switch in the bootstrap that changes which configuration file is loaded. Just remember that your development database often contains more data than a single unit test needs, and you probably hand-crafted that data and do not want to lose. Also, another database does not cost money.

    Should I clean the new database each after each test?

    I mostly clean the tables only that will be used in the test. Cleaning your database makes sure you don't get side-effects from previous tests.

    狂之美人 2024-11-05 22:11:54

    查看 Phactory。与 PHPUnit 中包含的数据库扩展相比,我更喜欢它,它使将记录插入测试数据库变得非常容易。

    require_once 'Phactory/lib/Phactory.php';
    
    Phactory::setConnection(new PDO('sqlite:test.db'));
    
    Phactory::define('user', array('name'  => 'Test User',
                                   'email' => '[email protected]'));
    
    $user = Phactory::create('user'); // creates a row in the 'users' table
    
    print("Hello, {$user->name}!"); // prints "Hello, Test User!"
    

    您的被测系统 (SUT) 将需要连接到您的测试数据库。这个想法是您只填充正在测试的方法所需的记录。如果测试数据库具有与生产数据库相同的表和字段,则 orm 层应该不重要。

    Check out Phactory. I prefer it over the database extensions included in PHPUnit and it makes it really easy to insert records into your test db.

    require_once 'Phactory/lib/Phactory.php';
    
    Phactory::setConnection(new PDO('sqlite:test.db'));
    
    Phactory::define('user', array('name'  => 'Test User',
                                   'email' => '[email protected]'));
    
    $user = Phactory::create('user'); // creates a row in the 'users' table
    
    print("Hello, {$user->name}!"); // prints "Hello, Test User!"
    

    Your System Under Test (SUT) will need to connect to your test database. The idea is that you populate just the records you need for the method you are testing. The orm layer shouldn't matter if the test db has all the same tables and fields as your production database.

    梦冥 2024-11-05 22:11:54

    PHPUnit 还为此提供了一些帮助,请查看数据库测试

    本质上,您可以编写测试类,以便它们扩展 PHPUnit_Extensions_Database_TestCase,然后使用 getConnection()getDataSet() 函数加载数据测试。

    require_once 'PHPUnit/Extensions/Database/TestCase.php';
    
    class PersonTest extends PHPUnit_Extensions_Database_TestCase
    {
        protected function getConnection() {
            $pdo = new PDO('mysql:host=localhost;dbname=application_test', 'root', '');
            return $this->createDefaultDBConnection($pdo, 'application_test');
        }
    
        protected function getDataSet() {
            return $this->createMySQLXMLDataSet('person.xml');
        }
    

    然后,您可以在 XML 中准确定义要在数据库中测试的内容。

    您还可以断言测试生成的 DataSet 等于您的预期:

    public function testCreate() {
        // Execute some code with your ORM to create a person.
    
        $actual = new PHPUnit_Extensions_Database_DataSet_QueryDataSet($this->getConnection());
        $actual->addTable('person');
        $expected = $this->createMySQLXMLDataSet('person_create_expected.xml');
        $this->assertDataSetsEqual($expected, $actual);
    }
    

    在本例中,我们仅比较生成的 person 表...因此 person_create_expected.xml 也应该只包含 person 表。

    要创建 XML,您可以使用 mysqldump。

    mysqldump --xml -t -u root -p application_test > person.xml
    

    PHPUnit also provides some help with this, have a look at Database Testing.

    Essentially you can write you Test classes so that they extend PHPUnit_Extensions_Database_TestCase and then use the getConnection() and getDataSet() functions to load up data for the test.

    require_once 'PHPUnit/Extensions/Database/TestCase.php';
    
    class PersonTest extends PHPUnit_Extensions_Database_TestCase
    {
        protected function getConnection() {
            $pdo = new PDO('mysql:host=localhost;dbname=application_test', 'root', '');
            return $this->createDefaultDBConnection($pdo, 'application_test');
        }
    
        protected function getDataSet() {
            return $this->createMySQLXMLDataSet('person.xml');
        }
    

    Then you can define exactly what you want to test in the database in the XML.

    You can also assert that the resulting DataSet from your tests is equal to what you expect with:

    public function testCreate() {
        // Execute some code with your ORM to create a person.
    
        $actual = new PHPUnit_Extensions_Database_DataSet_QueryDataSet($this->getConnection());
        $actual->addTable('person');
        $expected = $this->createMySQLXMLDataSet('person_create_expected.xml');
        $this->assertDataSetsEqual($expected, $actual);
    }
    

    In this example, we are only comparing the resulting person table... So person_create_expected.xml should only contain the person table as well.

    To create the XML's you can use mysqldump.

    mysqldump --xml -t -u root -p application_test > person.xml
    
    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文