返回值并在其他测试类中使用Phpunit

发布于 2025-02-04 15:51:12 字数 1409 浏览 3 评论 0 原文

如何返回一些值并在多个测试中使用它?使用@depends 变得有些混乱且棘手,在某些情况下,我需要从2个单独的方法中使用返回的值。

我克隆了数据库,现在我测试了将新客户插入数据库。我想要的是返回他的自动生成的customer_id,并将其用于班级以外的其他测试(例如,为该客户插入新地址)。就像我说的那样,我尝试使用@depperiands 尝试,但这很混乱,测试的顺序是错误的。

customerrepositorytest.php

    /**
     * @return int
     */
    public function testInsertNewCustomer(): int
    {
        $newCustomer = $this->customerRepository->insertNewUser('testuser.test.com', 'password', 'test', 'user');

        $this->assertIsInt($newCustomer);
        $this->assertGreaterThanOrEqual(0, $newCustomer);
        $this->assertNotEmpty($newCustomer);

        return $newCustomer;
    }

adverseRepositoryTest.php 在这里,我想使用新鲜创建的客户ID,该ID是自动增加的。

    /**
     * @depends CustomerRepositoryTest::testInsertNewCustomer 
     */
    public function testInsertNewAddress(int $newCustomer): void
    {
        $this->dropData('address');
        $insertAddress = $this->addressRepository->insertNewAddress($newCustomer, 'Test Street', 'Test', 22222, 'Test', 'billing');

        $this->assertIsInt($insertAddress);
        $this->assertNotFalse($insertAddress);
        $this->assertNotInstanceOf(AddressModel::class, $insertAddress);
        $this->assertIsNotBool($insertAddress);

        return $insertAddress;
    }

How can I return some value, and to use it on multiple tests? With @depends gets kind of messy and tricky, and there are some situations where I need to use returned values from 2 separate methods.

I cloned my database, and I right now, I tested inserting new customer to database. What I want is to return his automatically generated customer_id, and to use it on other tests outside of the class (For example, test inserting new address for that customer). Like I said, I tried with with @depends, but it is messy, and the order of the testings are false.

CustomerRepositoryTest.php

    /**
     * @return int
     */
    public function testInsertNewCustomer(): int
    {
        $newCustomer = $this->customerRepository->insertNewUser('testuser.test.com', 'password', 'test', 'user');

        $this->assertIsInt($newCustomer);
        $this->assertGreaterThanOrEqual(0, $newCustomer);
        $this->assertNotEmpty($newCustomer);

        return $newCustomer;
    }

AddressRepositoryTest.php
Here I want to use freshly created customer id, which is auto incremented.

    /**
     * @depends CustomerRepositoryTest::testInsertNewCustomer 
     */
    public function testInsertNewAddress(int $newCustomer): void
    {
        $this->dropData('address');
        $insertAddress = $this->addressRepository->insertNewAddress($newCustomer, 'Test Street', 'Test', 22222, 'Test', 'billing');

        $this->assertIsInt($insertAddress);
        $this->assertNotFalse($insertAddress);
        $this->assertNotInstanceOf(AddressModel::class, $insertAddress);
        $this->assertIsNotBool($insertAddress);

        return $insertAddress;
    }

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

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

发布评论

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

评论(1

难如初 2025-02-11 15:51:12

我克隆了我的数据库,现在我测试了将新客户插入数据库。我想要的是返回他的自动生成的customer_id,并将其在类外的其他测试中使用

,假设您将数据库克隆到数据库中以具有用于测试的数据库,这就是对此类custernal_id的需求(并且有可能更多此类关键像各种ID这样的数据点)从中生长。

这样的测试数据库通常称为A 测试固定装置或Just fixture 。您想使用该固定装置进行测试,在您的情况下是测试数据库。

我现在不现在就看一下这意味着您的测试意味着什么,我希望您指向Phpunit文档,该文档描述了Phpunit如何支持测试固定件

您将找到一种方法设置每个测试。由于您可以扩展基本测试柜,因此可以使其成为所有测试的模板,这些测试从基本测试案例中延伸到您的测试套件中。

在非常简单的示例中,它看起来可能是:

abstract class CustomerDatabaseTestCase extends TestCase
{
    protected $customer_id;

    public function setUp(): void
    {
        $this->customer_id = 42; /* PUT YOUR MAGIC NUMBER HERE */
    }
}

从测试案例延伸,然后允许您在测试中访问 $ this-culting_id 的客户ID。

归根结底,这只是标准的面向对象的编程,遵循语言在继承和可见性方面的规则。

@Depends 在您的方案中不适合(井),因为您有一个真实的固定装置,并且您不想使单个测试方法取决于其他测试方法,因为您也想执行执行这些测试方法彼此隔离(迟早),并引入@depperiands 使它们取决于它们,因此将竭尽所能。

现在,在非常一般的层面上,您的如何做到这一点。

使用您自己控制的基本测试案例,您可以将测试代码分组并控制固定装置。如果您仔细阅读了有关此文件的Phpunit文档,您将已经得到一些指针,因为没有免费午餐,因此(重)固定装置会导致什么。

因此,让我们看一点一点,为什么,即使我们开始意识到固定装置可能会成为负担,如果需要,我们仍然会做。这是因为运行测试的好处正在运行它们自动化。

自动化测试使我们可以(或多或少)快速迭代开发,而运行测试。我们得到直接而快速的反馈。

我们甚至在知道固定装置可能会成为这里的负担的同时这样做。以测试数据库为例:一个测试插入记录,而另一个测试需要记录来测试不同的内容。因此,固定装置本身可以变得脆弱,重量和/或昂贵。

虽然一种方法是减少固定装置,例如,您只能从数据库基准测试案例中扩展这些测试案例, 实际上相关的测试彼此独有的)是自动化测试数据库的设置,以便一旦整体测试固定悬挂,您就可以自动设置固定装置,并且总是(至少)(至少)定义得很好 - 就像往常一样。

例如,您可以在phpunit中添加一个bootstrap文件还设置测试数据库。虽然您可以在数据库基准测试案例的设置方法中执行此操作,但您会很快注意到它在每个 之前运行测试方法。因此,如果您需要在那里进行昂贵的操作(例如,设置测试数据库需要几秒钟),则每个 的运行时间将通过该数量的秒数放大。将其乘以测试数量,您会发现测试套件的总运行时间快速增长。

您的测试的较大运行时间会降低整体进度,因为您再也无法快速获得反馈,这首先是进行Phpunit测试的关键驱动力之一。

因此, fixtures 的主题并不是一个完全容易的话题。尤其是在测试中进行更多重型系统 - 例如一个大型测试数据库 - 您将面临现实,并且需要根据固定装置在固定装置上找到这些测试 的良好妥协。好消息是,随着测试的自动运行,您也可以在这里快速播放,并立即与测试套件的运行时间进行检查是否有益,这使您可以做出更改的决定快速地。

  • 首先尝试您的测试以完全不需要固定装置。
  • 如果不可能,请尝试保持固定装置较低。
  • 仅使用@depends 当您需要测试方法的某个顺序时(例如,首先创建数据库行,然后在第二个测试方法中进行操作)。也尝试防止这一点。
  • 设置了任何测试数据库自动化的设置,以便您可以在运行之前运行测试套件,就好像它不存在(并且运行测试可能会在发生错误时损坏甚至完全销毁它)。

如果您使用库进行数据库访问,还可以使用库文档检查其提供的测试实用性。一个好的图书馆具有测试适配器或至少测试支持,因此您可以更倾向于(更快,更脆)的单位测试,而不是需要写入(更重,更慢,更慢,维护)集成测试(请参阅测试 - pyramid并了解为什么集成测试会导致“测试粉末”)。

Phpunit文档还具有一些好的关键指针,如何设计自己的测试套件以获得并保持运行测试套件的好处。

还有一些警告,以便我明确说明:如果您在上面搜索phpunit,请注意,有多少人问有多少数据库测试。很容易遇到更复杂的问题(测试固定装置!)。

这应该作为标志。如果代码难以测试,请考虑更改代码的设计,以便易于测试(在几秒钟内进行整体测试套件运行,而不是分钟)。专注于您的生产代码,而不是测试代码,因此仅通过对测试套件本身的最小修改而更改,因为它是中央开发依赖性,如果它破裂,您将停止测试直到修复它。因此,它可以很容易地成为表演的阻止者。这是不惜一切代价避免的,并且成本尽可能少。

愉快的测试。

I cloned my database, and I right now, I tested inserting new customer to database. What I want is to return his automatically generated customer_id, and to use it on other tests outside of the class

Assuming you cloned the database to have a database for testing and this is where the need of such a customer_id (and potentially more of such key data-points like IDs of all kinds) grows from.

Such a test database is commonly called a Test Fixture or just Fixture in short. You want to run your tests with that fixture, in your case the test-database.

Without looking right now what this implies for your tests first, I'd like you to point to the Phpunit documentation which describes how Phpunit supports Test Fixtures:

You will find a way to setUp each test. As you can extend the base TestCase, you can make it a template for all of your tests that extend from a base test-case you introduce yourself in your test-suite.

In the very simplistic example, it could look like:

abstract class CustomerDatabaseTestCase extends TestCase
{
    protected $customer_id;

    public function setUp(): void
    {
        $this->customer_id = 42; /* PUT YOUR MAGIC NUMBER HERE */
    }
}

Extending from that test-case then allows you to access the customer id by $this->customer_id within your tests.

At the end of the day, this is just standard PHP object oriented programming and follows the rule of the language in regards of inheritance and visibility.

@depends is not (well) fitting in your scenario, as you have a true fixture and you don't want to make individual test-methods depend on other test-methods, because you also want to execute these test-methods isolated to each other (sooner or later) and introducing @depends make them dependent and therefore will stand in your way to this regard.

Now so much on the very general level how you could do this.

Using a base-test-case you control your own allows you to group test-code and also to control the fixture. If you read the Phpunit documentation regarding this carefully you'll already get some pointers what (heavy) fixtures can lead to, as there is no free lunch.

So lets look a little bit why, even we start to realize that fixtures can become a burden, we still do them if needed. And that is because the benefit of running the tests is running them automated.

Automated tests allow us to (more or less) quickly iterate with the development while running the tests. We get direct and fast feedback.

We even do this while we know that fixtures can become a burden here. Take a test-database as an example: One test inserts a record while another test needs that record to test something different. So a fixture can become brittle or heavy and/or expensive by itself.

While one way then is to reduce the fixture, e.g. you could only extend those test-cases from the database-base-test-case that are actually database related tests, another (and both ways aren't exclusive to each other) is to automate the setup of your test-database so that once your overall test-fixture went dangling, you have an automated way to setup the fixture and it is always (at least) well defined - like always.

For example, you could add a bootstrap file in Phpunit that takes care of setting up the test database as well. While you could do that in the setUp method of the database-base-test-case, you'll soon notice that it runs before every test-method. So if you need to do expensive operations there (like setting up the test-database takes some seconds), the run-time of each test would be enlarged by that amount of seconds. Multiply it with the number of tests and you'll find the overall run-time of your test-suite to grow fast.

A larger run-time of your tests then degrades the overall progress as you don't get feedback fast any longer which is one of the key drivers to do the Phpunit tests in the first place.

Therefore the topic of Fixtures is not an entirely easy one. Especially with more heavy systems under test - e.g. a big test-database - you'll face the reality and the need to find a good compromise for those tests depending on a fixture. The good news is, as the tests run automated, you can play fast here as well and check with the run-time of the test-suite immediately if a change of your tests is of benefit or not which allows you to make decisions of change fast.

  • First try your tests to not need a fixture at all.
  • If not possible try to keep the fixture low.
  • Only use @depends when you need a certain order for the test-methods (e.g. first creating a database row, then operating on it in the second test method). Try to prevent that as well.
  • Have the setup of any test-database automated so that you can run the test-suite as if it didn't exist before that run (and that running the tests can damage or even fully destroy it in case of an error).

If you use a library for database access, also check with the library documentation which test-utilities it provides. A good library has test-adapters or at least test-support so that you can lean more towards (faster and less brittle) unit-tests instead of the need to write (more heavy, slower and maintenance intensive) integration tests (see the test-pyramid and learn why integration tests can lead to a "testing tarpit").

The Phpunit documentation also has some good key pointers how to design ones own test-suite to get and keep having benefits of running a test-suite.

And some word of warning just so that I have made this clear: If you search for Phpunit on SO, keep an eye how many are asking about testing with databases. It is easy to run into more complicated problems with it (Test Fixtures !).

This should be taken as a sign. If code is hard to test, consider changing the design of your code so that it becomes easy to test (have the overall test-suite run in seconds, not minutes). Focus on your production code, not the test-code, so do these changes only with the littlest modifications to the test-suite itself as it is a central development dependency and if it breaks, you will stop testing until you fix it. So it can easily become a show stopper. This is to be avoided at all costs and with as little cost as necessary.

Happy testing.

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