PHPUnit:对非公共变量进行断言

发布于 2024-12-28 06:41:27 字数 1262 浏览 5 评论 0原文

假设我有一个具有私有属性和关联的公共 getter 和 setter 的类。我想使用 PHPUnit 测试该属性在使用 setter 后是否获得正确的值,或者 getter 返回正确的属性。

当然,我可以通过使用 getter 来测试 setter,以查看对象是否存储了正确的值,反之亦然来测试 getter。然而,这并不能保证私有财产就是被设置的财产。

假设我有以下课程。我创建了一个属性、getter 和 setter。但我在属性名称中犯了一个拼写错误,因此 getter 和 setter 实际上并没有操纵它们应该操纵的属性。

class SomeClass
{
    private 
        $mane = NULL; // Was supposed to be $name but got fat-fingered!

    public function getName ()
    {
        return ($this -> name);
    }

    public function setName ($newName)
    {
        $this -> name = $newName;
        return ($this);
    }
}

如果我运行以下测试,

public function testSetName ()
{
    $this -> object -> setName ('Gerald');
    $this -> assertTrue ($this -> object -> getName () == 'Gerald');
}

我将获得通过。然而,我不希望发生的非常糟糕的事情却发生了。当调用 setName() 时,它实际上在类中创建了一个新属性,其名称是我认为是私有属性的名称,只有 setter 创建的属性是公共的!我可以用下面的代码来演示:

$a  = new SomeClass;

$a -> setName('gerald');
var_dump ($a -> getName ());
var_dump ($a -> name);

它将输出:

字符串(6)“杰拉德”

字符串(6)“杰拉德”

有什么方法可以从 PHPUnit 访问私有属性,这样我就可以编写测试来确保我认为正在获取和设置的属性实际上正在获取和设置放?

或者我应该在测试中做一些其他事情来捕获这样的问题,而不尝试访问被测对象的私有状态?

Suppose I have a class with a private property and associated public getter and setter. I want to test with PHPUnit that the property gets the correct value after the setter has been used or that the getter returns the correct property.

Of course I can test the setter by using the getter to see that the object is storing the correct value, and vice versa for testing the getter. However, this doesn't guarantee that the private property is the one being set.

Say I had the following class. I created a property, getter and setter. But I made a typo in the property name, so the getter and the setter don't actually manipulate the property they're meant to manipulate

class SomeClass
{
    private 
        $mane = NULL; // Was supposed to be $name but got fat-fingered!

    public function getName ()
    {
        return ($this -> name);
    }

    public function setName ($newName)
    {
        $this -> name = $newName;
        return ($this);
    }
}

If I run the following test

public function testSetName ()
{
    $this -> object -> setName ('Gerald');
    $this -> assertTrue ($this -> object -> getName () == 'Gerald');
}

I would get a pass. However, something very bad has actually happened that I don't want. When setName() is called, it actually creates a new property in the class with the name I thought my private property had, only the one that the setter creates is public! I can demonstrate that with the following code:

$a  = new SomeClass;

$a -> setName('gerald');
var_dump ($a -> getName ());
var_dump ($a -> name);

It would output:

string(6) "gerald"

string(6) "gerald"

Is there any way I can access the private properties from PHPUnit so I can write tests that make sure that the properties I think are being get and set actually really are being get and set?

Or is there some other thing I should be doing in a test to catch problems like this without trying to get access to the private state of the object under test?

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

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

发布评论

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

评论(4

凉栀 2025-01-04 06:41:27

您还可以使用 Assert::assertAttributeEquals('value', 'propertyName', $object)

请参阅https://github.com/sebastianbergmann/phpunit/blob/3.7/PHPUnit /Framework/Assert.php#L490

You can also use Assert::assertAttributeEquals('value', 'propertyName', $object).

See https://github.com/sebastianbergmann/phpunit/blob/3.7/PHPUnit/Framework/Assert.php#L490

情域 2025-01-04 06:41:27

对于测试属性,我会提出与测试私有方法时相同的论点。

您通常不想这样做< /strong>

这是关于测试可观察的行为。

如果您重命名所有属性或决定将它们存储到数组中,则根本不需要调整您的测试。您希望测试告诉您一切仍然有效!当您需要更改测试以确保一切仍然有效时,您将失去所有好处,因为更改测试也可能会出错。

因此,总而言之,您失去了测试套件的价值!


仅仅测试 get/set 组合就足够了,但通常不是每个 setter 都应该有 getter,并且仅仅创建它们用于测试并不是一件好事。

通常,您设置一些内容,然后告诉该方法执行某些操作(行为)。对此进行测试(该类做了应该做的事情)是测试的最佳选择,并且应该使测试属性变得多余。


如果你真的想这样做,PHP 反射 API 中有 setAccessible 功能,但我无法举出一个例子来说明这一点:找到

未使用的属性来捕获像这样的错误/问题 PHP 混乱检测器 作为 UnusedPrivateField Rule

class Something
{
    private static $FOO = 2; // Unused
    private $i = 5; // Unused
    private $j = 6;
    public function addOne()
    {
        return $this->j++;
    }
}

这将为您生成两个警告,因为从未访问过变量

For testing properties, I'd make the same arguments I make then talking about testing private methods.

You usually don't want to do this.

It's about testing observable behavior.

If you rename all your properties or decide to store them into an array you should not need to adapt your tests at all. You want your tests to tell you that everything still works! When you need to change the tests to make sure everything still works you lose all the benefits as you also could make an error changing the tests.

So, all in all, you lose the value of you test suite!


Just testing the get/set combinations would be ok enough but usually not every setter should have a getter and just creating them for testing is not a nice thing ether.

Usually, you set some stuff and then tell the method to DO (behavior) something. Testing for that (that the class does what is should do) is the best option for testing and should make testing the properties superfluous.


If you really want to do that there is the setAccessible functionality in PHP reflections API but I can't make up an example where I find this desirable

Finding unused properties to catch bugs / issues like this one:

The PHP Mess Detector As a UnusedPrivateField Rule

class Something
{
    private static $FOO = 2; // Unused
    private $i = 5; // Unused
    private $j = 6;
    public function addOne()
    {
        return $this->j++;
    }
}

This will generate two warnings for you because the variables are never accessed

孤独患者 2025-01-04 06:41:27

我只想指出一件事。让我们暂时忘记私有字段,专注于您班级的客户所关心的内容。您的类公开了一个契约,在本例中 - 更改和检索名称的能力(通过 getter 和 setter)。预期的功能很简单:

  • 当我使用 setName 将名称设置为 "Gerald" 时,我希望在调用 时得到 "Gerald" getName

就这些了。客户不会(好吧,不应该!)关心内部实现。无论您使用私有字段名称、哈希集还是通过动态生成的代码调用 Web 服务 - 对于客户端来说都无关紧要。从用户的角度来看,您当前遇到的错误根本不是错误。

PHPUnit 是否允许您测试私有变量 - 我不知道。但从单元测试的角度来看,你不应该这样做。

编辑(回应评论):

我理解您对内部状态可能暴露的担忧,但我认为单元测试不是解决这个问题的正确工具。您可以想出很多可能的场景,某事可能会做其他未计划的事情。单元测试绝不是包治百病的良药,也不应该这样使用。

I just want to point out one thing. Let's forget about private fields for a moment and focus on what client of your class cares about. Your class exposes a contract, in this case - ability to alter and retrieve name (via getter and setter). Expected functionality is simple:

  • when I set name with setName to "Gerald", I expect to get "Gerald" when I call getName

That's all. Client won't (well, shouldn't!) care about internal implementation. Whether you used private field name, hashset or called web service via dynamically generated code - doesn't matter for client. The bug you are currently experiencing, from user point of view - is not a bug at all.

Whether PHPUnit allows you to test private variables - I don't know. But from unit-testing perspective, you shouldn't do that.

Edit (in response to comment):

I understand your concerns about possible exposure of internal state, however I don't think unit testing is the right tool to deal with that. You can come up with a lot of possible scenarios how something might do something else which wasn't planned. Unit tests are by no means cure for all and shouldn't be used as such.

鹿港巷口少年归 2025-01-04 06:41:27

我同意其他人的观点,一般来说,您希望避免在测试中访问私有内容,但对于需要的情况,您可以 使用反射读写属性

I agree with the others that in general you want to avoid accessing privates in your tests, but for the cases where you need to, you can use reflection to read and write the property.

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