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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8928905/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 05:48:05  来源:igfitidea点击:

PHPUnit: Doing assertions on non-public variables

phpunit-testingphpunitwhite-box

提问by GordonM

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.

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

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.

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

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

假设我有以下课程。我创建了一个属性,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);
    }
}

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:

我会得到通行证。然而,实际上发生了一些我不想要的非常糟糕的事情。当 setName() 被调用时,它实际上在类中创建了一个新属性,名称为我认为我的私有属性,只有 setter 创建的属性是公共的!我可以用以下代码证明这一点:

$a  = new SomeClass;

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

It would output:

它会输出:

string(6) "gerald"

string(6) "gerald"

字符串(6)“杰拉德”

字符串(6)“杰拉德”

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?

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

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?

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

采纳答案by edorian

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.

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 changethe 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.

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

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.

通常,你设置一些东西,然后告诉方法DO(行为)一些东西。对此进行测试(类做应该做的事情)是测试的最佳选择,并且应该使测试属性变得多余。



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

如果你真的想这样做,setAccessiblePHP 反射 API中有这个功能,但我不能举一个我觉得这很可取的例子

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

查找未使用的属性以捕获像这样的错误/问题:

The PHP Mess DetectorAs a UnusedPrivateField Rule

PHP混乱探测器作为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

这将为您生成两个警告,因为永远不会访问变量

回答by Gildas

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

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

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

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

回答by k.m

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:

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

  • when I set name with setNameto "Gerald", I expect to get "Gerald"when I call getName
  • 当我用setNameto设置 name 时"Gerald",我希望"Gerald"在我打电话时得到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 bugyou are currently experiencing, from user point of view - is not a bug at all.

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

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

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

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 somethingmight do something elsewhich wasn't planned. Unit tests are by no means cure for all and shouldn't be used as such.

我理解您对可能暴露内部状态的担忧,但是我认为单元测试不是处理这种情况的正确工具。你可以想出很多可能的场景,有些事情可能会做一些没有计划的事情。单元测试绝不是万能的,不应如此使用。

回答by David Harkness

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.

我同意其他人的看法,通常您希望避免在测试中访问私有属性,但对于需要的情况,您可以使用反射来读取和写入属性