การทดสอบคลาสนามธรรม


144

ฉันจะทดสอบวิธีที่เป็นรูปธรรมของคลาสนามธรรมด้วย PHPUnit ได้อย่างไร

ฉันคาดหวังว่าฉันจะต้องสร้างวัตถุบางอย่างเป็นส่วนหนึ่งของการทดสอบ แม้ว่าฉันไม่ทราบวิธีปฏิบัติที่ดีที่สุดสำหรับสิ่งนี้หรือถ้า PHPUnit อนุญาตสำหรับสิ่งนี้


10
บางทีคุณควรพิจารณาเปลี่ยนคำตอบที่ยอมรับ
จาค็อบ

1
บางทีstackoverflow.com/a/2947823/23963อาจช่วยได้
Nigel Thorne

คำตอบ:


240

การทดสอบหน่วยของคลาสนามธรรมไม่จำเป็นต้องหมายถึงการทดสอบอินเตอร์เฟสเนื่องจากคลาสนามธรรมสามารถมีวิธีที่เป็นรูปธรรมและสามารถทดสอบวิธีที่เป็นรูปธรรมนี้ได้

ไม่ใช่เรื่องแปลกเมื่อเขียนโค้ดไลบรารีเพื่อให้มีคลาสพื้นฐานที่คุณคาดว่าจะขยายในเลเยอร์แอปพลิเคชันของคุณ และถ้าคุณต้องการตรวจสอบให้แน่ใจว่ามีการทดสอบรหัสห้องสมุดคุณต้องใช้วิธีการที่เป็นรูปธรรมของคลาสนามธรรม

ส่วนตัวผมใช้ PHPUnit และมันมีชื่อเรียกว่า stubs และ mock objects เพื่อช่วยคุณทดสอบสิ่งต่าง ๆ

ส่งตรงจากคู่มือ PHPUnit :

abstract class AbstractClass
{
    public function concreteMethod()
    {
        return $this->abstractMethod();
    }

    public abstract function abstractMethod();
}

class AbstractClassTest extends PHPUnit_Framework_TestCase
{
    public function testConcreteMethod()
    {
        $stub = $this->getMockForAbstractClass('AbstractClass');
        $stub->expects($this->any())
             ->method('abstractMethod')
             ->will($this->returnValue(TRUE));

        $this->assertTrue($stub->concreteMethod());
    }
}

วัตถุจำลองให้คุณหลายสิ่ง:

  • คุณไม่จำเป็นต้องมีการใช้คลาสนามธรรมอย่างเป็นรูปธรรมและสามารถออกไปกับต้นขั้วแทน
  • คุณอาจเรียกวิธีการที่เป็นรูปธรรมและยืนยันว่าวิธีการเหล่านั้นทำงานได้อย่างถูกต้อง
  • หากวิธีคอนกรีตอาศัยวิธีการที่ไม่ได้ดำเนินการ (นามธรรม) คุณอาจไม่สนใจค่าตอบแทนด้วยวิธี () วิธี PHPUnit

38

นั่นเป็นคำถามที่ดี ฉันกำลังมองหาสิ่งนี้เช่นกัน
โชคดีที่ PHPUnit แล้วมีgetMockForAbstractClass()วิธีการสำหรับกรณีนี้เช่น

protected function setUp()
{
    $stub = $this->getMockForAbstractClass('Some_Abstract_Class');
    $this->_object = $stub;
}

สำคัญ:

โปรดทราบว่าต้องใช้ PHPUnit> 3.5.4 มีข้อผิดพลาดในรุ่นก่อนหน้า

ในการอัพเกรดเป็นเวอร์ชั่นใหม่ล่าสุด:

sudo pear channel-update pear.phpunit.de
sudo pear upgrade phpunit/PHPUnit

ฟังดูน่าสนใจ แต่คุณจะทดสอบกับคนล้อเลียน? การทดสอบจะเป็นอย่างไร? IE: ขยายการเยาะเย้ยในกรณีทดสอบและการทดสอบกับระดับการทดสอบขยาย?
stefgosselin

34

ควรสังเกตว่ามีการเพิ่มการรองรับ PHP 7 สำหรับคลาสที่ไม่ระบุชื่อ สิ่งนี้ทำให้คุณมีช่องทางเพิ่มเติมสำหรับการตั้งค่าการทดสอบสำหรับคลาสนามธรรมซึ่งไม่ขึ้นอยู่กับฟังก์ชันการทำงานเฉพาะของ PHPUnit

class AbstractClassTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var AbstractClass
     */
    private $testedClass;

    public function setUp()
    {
        $this->testedClass = new class extends AbstractClass {

            protected function abstractMethod()
            {
                // Put a barebones implementation here
            }
        };
    }

    // Put your tests here
}

4
ขอบคุณสำหรับสิ่งนี้! การใช้คลาสที่ไม่ระบุชื่อใน PHPUnit ทำให้ฉันมีความยืดหยุ่นอย่างมากในการสร้างการทดสอบต่างๆของฉัน
Alice Wonder

1

Eran วิธีการของคุณควรใช้งานได้ แต่มันขัดกับแนวโน้มของการเขียนแบบทดสอบก่อนรหัสจริง

สิ่งที่ฉันอยากจะแนะนำคือการเขียนการทดสอบของคุณเกี่ยวกับการทำงานที่ต้องการของคลาสย่อยที่ไม่ใช่นามธรรมของคลาสนามธรรมที่เป็นปัญหาจากนั้นเขียนทั้งคลาสนามธรรมและคลาสย่อยที่ใช้งานและในที่สุดก็รันการทดสอบ

การทดสอบของคุณควรทดสอบวิธีที่กำหนดของคลาสนามธรรม แต่ผ่านคลาสย่อยเสมอ


ฉันพบว่าเป็นคำตอบโดยพลการ: คุณมีคลาสนามธรรม 'A' ที่มีวิธีการ 'foo ()' ร่วมกัน วิธีการ 'foo ()' นี้มีการใช้งานโดยรวม 'B' และคลาส 'C' โดยรวมซึ่งมาจาก 'A' คลาสใดที่คุณจะเลือกทดสอบ 'foo ()'
user3790897

1

คำตอบของเนลสันนั้นผิด

คลาสนามธรรมไม่ต้องการวิธีการทั้งหมดเพื่อให้เป็นนามธรรม

วิธีการใช้งานเป็นวิธีที่เราต้องทดสอบ

สิ่งที่คุณสามารถทำได้คือสร้างคลาสสตับปลอมในไฟล์ทดสอบหน่วยขยายคลาสนามธรรมและใช้เฉพาะสิ่งที่ต้องการโดยไม่มีฟังก์ชั่นการใช้งานทั้งหมดและทดสอบสิ่งนั้น

ไชโย


0

หากคุณไม่ต้องการซับคลาสคลาสนามธรรมเพียงเพื่อทำการทดสอบหน่วยเกี่ยวกับวิธีการที่นำไปใช้ในคลาสนามธรรมแล้วคุณสามารถลองดูว่ากรอบงานของคุณอนุญาตให้คุณจำลองคลาสนามธรรมหรือไม่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.