【问题标题】:Using Reflection to set Properties in an Unit Test在单元测试中使用反射设置属性
【发布时间】:2017-10-30 19:20:44
【问题描述】:

这是我的场景:

我创建了一个抽象类来减少代码重复,并强制一些方法由扩展这个类的具体类来实现。

抽象类 BaseClass { 受保护的 $arrayField; ... 公共函数 getModifiedArrayField($constraints) { // 对 $arrayField 做一些事情并返回一个修改过的 // 数组字段的版本。仅取决于 // $constraints 和一些 `array_*` 函数 返回 $modifiedArray; } // ... 其他一些减少代码重复的方法 // ... 需要实现的抽象方法 }

我认为在抽象类本身中测试具体方法是个好主意。

$arrayField 将由具体类中的抽象方法填充。

由于我想测试修改该属性(但不改变)的方法的功能,我编写了一个单元测试,如下所示。

类 BaseClassTest 范围 PHPUnit_Framework_TestCase 私人 $sut; 公共函数设置() { $mockObj = $this->getMockFromAbstractClass(BaseClass::class); $ref = new ReflectionClass($mockObj); $ref_prop = $ref->getProperty('arrayField'); $ref_prop->setAccessible(true); $ref_prop->setValue($mockObj, [an_array]); $this->sut = $mockObj; } // .. 一些测试抽象类方法的测试方法 公共函数 testGetModifiedArrayFieldReturnsExpectedArray() { $expected = [array_i_expect]; $actual = $this->sut->getModifiedArrayField([constraints_i_provide]); $this->assertEquals($expected, $actual); }

现在,我读到使用反射来更改可见性只是为了测试并不是一个好习惯。

所以我有两个问题:

  1. 测试社区是否认为这种方法只是“轻罪”而不是大罪?
  2. 我应该以不同的方式设计这个类,以便我可以摆脱反射吗?如果是,您有什么建议的方法吗?

更新:

Schleisanswer 引起了我的思考,在与朋友聊天并在 Internet 上获取了一些资源后,我选择通过在我需要测试的函数中引入一个额外的参数来解决这个问题。

我将进一步尝试概括该函数并将其移至 ArrayHelper 类,这使得 1) 测试更容易,2) 允许代码的其他部分在需要时使用该方法。

【问题讨论】:

    标签: php unit-testing phpunit


    【解决方案1】:

    使用反射的问题是你暴露了类的内部。单元测试有助于证明您的代码正常工作,但也允许您重构事物并验证您没有更改任何当前功能。

    因此,使用反射来更改内部属性的可见性意味着您可以稍后删除/更改该属性。例如,您可能会发现您可以即时计算或类似的方式。

    很难测试一个类是代码异味。

    为什么$arrayField 只能通过抽象方法设置?如果我在调用getModifiedArrayField() 之前没有在此类的实现中调用该方法会怎样?

    很难根据帖子中的名称和描述来判断您对此类和方法的意图。但是,我认为您可能需要更多地考虑您希望您的班级做什么。并更改您的类以要求在构造函数中提供$arrayField 或提供一个简单的公共方法来设置此类中的值。

    【讨论】:

    • 感谢您的回答。关于您的问题:抽象方法就像一个水合器,它从数据提供者中填充arrayField 的值。我想测试的方法只是将数据转换为不同的格式,以便预先存在的代码库可以对返回的数据执行其操作。我想一个更好的主意是将转换移动到一个单独的类并在这个类返回的任何东西上运行它,或者只是将一个额外的参数传递给函数,尽管我不太确定它的性能开销。跨度>
    猜你喜欢
    • 2011-03-13
    • 2023-04-02
    • 2013-03-03
    • 2014-08-16
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    相关资源
    最近更新 更多