以下是我的情景:
我创建了一个抽象类来减少代码重复,并强制执行一些方法来扩展这个类的具体类。
abstract class BaseClass { protected $arrayField; ... public function getModifiedArrayField($constraints) { // do things to $arrayField and return a modified // version of the arrayField. Depends only on the // $constraints and some `array_*` functions return $modifiedArray; } // ... some other methods for reducing code duplication // ... abstract methods that needs to be implemented }
我认为在抽象类本身中测试具体方法是个好主意。
$arrayField
将由具体类中的抽象方法填充。
由于我想测试修改该属性的方法的功能(但不会改变),我写了一个单元测试如下。
class BaseClassTest extents PHPUnit_Framework_TestCase private $sut; public function setUp() { $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; } // .. some test methods that tests methods of abstract class public function testGetModifiedArrayFieldReturnsExpectedArray() { $expected = [array_i_expect]; $actual = $this->sut->getModifiedArrayField([constraints_i_provide]); $this->assertEquals($expected, $actual); }
现在,我读到,为了测试,使用Reflection来改变可见性并不是一个好习惯。
所以我有两个问题:
我将继续尝试概括函数并将其移动到ArrayHelper类,这使得1)更容易测试它2)如果需要,允许代码的其他部分使用该方法。
答案 0 :(得分:1)
使用反射的问题在于您正在暴露类内部。单元测试有助于证明您的代码正常工作,但也允许您重构事物并验证您没有更改任何当前功能。
因此,使用反射来更改内部属性的可见性意味着您可以稍后删除/更改该属性。例如,您可能会发现您可以即时计算它或类似的东西。
难以测试一个类是代码气味。
为什么$arrayField
只能通过抽象方法设置?如果我在调用getModifiedArrayField()
之前没有在该类的实现中调用该方法会发生什么?
根据帖子中的名称和描述,很难说出您对此类的意图以及方法。但是,我认为您可能需要考虑更多您希望班级做的事情。并更改您的类以要求在构造函数上提供$arrayField
或提供一个简单的公共方法来设置此类中的值。