简体   繁体   English

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

[英]PHPUnit: Doing assertions on non-public variables

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. 我想用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. 当然,我可以通过使用getter来测试对象,以查看对象存储的是正确的值,反之亦然,以测试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. 我创建了一个属性,getter和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实际上并没有操纵它们要操纵的属性

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! 调用setName()时,它实际上在该类中创建了一个新属性,其名称我认为我的私有属性具有该属性,只有setter创建的属性才是公共的! 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)“杰拉德”

string(6) "gerald" string(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? 还是我应该在测试中做其他事情来捕获这样的问题,而又不试图访问被测对象的私有状态?

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

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 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. 仅仅测试get / set组合就可以了,但是通常不是每个setter都应该有一个getter,而仅创建它们进行测试并不是一件好事。

Usually, you set some stuff and then tell the method to DO (behavior) something. 通常情况下,你设置一些东西,然后告诉法DO (行为)的东西。 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 如果您确实想这样做,则在PHP Reflections API中有setAccessible功能,但是我无法组成一个我认为很理想的示例

Finding unused properties to catch bugs / issues like this one: 查找未使用的属性来捕获此类错误/问题:

The PHP Mess Detector As 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 这将为您生成两个警告,因为从未访问过变量

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). 在这种情况下,您的班级公开了一项合同-能够更改和检索名称(通过getter和setter)。 Expected functionality is simple: 预期的功能很简单:

  • when I set name with setName to "Gerald" , I expect to get "Gerald" when I call getName 当我将setName名称设置为"Gerald" ,我期望在调用getName时得到"Gerald"

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. 通过动态生成的代码使用私有字段名称,哈希集还是调用Web服务-对客户端来说都无关紧要。 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. PHPUnit是否允许您测试私有变量-我不知道。 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. 单元测试绝不能解决所有问题,因此不应如此使用。

我同意其他人的看法,一般来说,您要避免在测试中访问私有数据,但是对于需要的情况,可以使用反射来读取和写入该属性

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM