Menguji Kelas Abstrak

144

Bagaimana cara menguji metode konkret dari kelas abstrak dengan PHPUnit?

Saya berharap bahwa saya harus membuat semacam objek sebagai bagian dari tes. Padahal, saya tidak tahu praktik terbaik untuk ini atau jika PHPUnit memungkinkan untuk ini.

Mez
sumber
10
Mungkin Anda harus mempertimbangkan untuk mengubah jawaban yang diterima.
Yakub
1
Mungkin stackoverflow.com/a/2947823/23963 akan membantu.
Nigel Thorne

Jawaban:

240

Unit testing kelas abstrak tidak perlu berarti menguji antarmuka, karena kelas abstrak dapat memiliki metode konkret, dan metode konkret ini dapat diuji.

Tidak jarang, ketika menulis beberapa kode pustaka, memiliki kelas dasar tertentu yang Anda harapkan untuk diperluas di lapisan aplikasi Anda. Dan jika Anda ingin memastikan bahwa kode perpustakaan diuji, Anda perlu sarana untuk UT metode konkret kelas abstrak.

Secara pribadi, saya menggunakan PHPUnit, dan itu disebut bertopik dan benda tiruan untuk membantu Anda menguji hal-hal semacam ini.

Langsung dari manual 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());
    }
}

Objek tiruan memberi Anda beberapa hal:

  • Anda tidak diharuskan untuk memiliki implementasi konkret dari kelas abstrak, dan dapat lolos dari rintisan sebagai gantinya
  • Anda dapat memanggil metode konkret dan menyatakan bahwa mereka melakukan dengan benar
  • jika metode konkret bergantung pada metode yang tidak diterapkan (abstrak), Anda dapat mematikan nilai pengembalian dengan kehendak () metode PHPUnit
Victor Farazdagi
sumber
38

Itu pertanyaan yang bagus. Saya sudah mencari ini juga.
Untungnya, PHPUnit sudah memiliki getMockForAbstractClass()metode untuk kasus ini, misalnya

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

Penting:

Perhatikan bahwa ini membutuhkan PHPUnit> 3.5.4. Ada bug di versi sebelumnya.

Untuk meningkatkan ke versi terbaru:

sudo pear channel-update pear.phpunit.de
sudo pear upgrade phpunit/PHPUnit
takeshin
sumber
Kedengarannya menarik tetapi Anda akan menguji terhadap mock? Seperti apa tes itu? IE: memperluas tiruan dalam kasus uji dan pengujian terhadap kelas uji diperpanjang?
stefgosselin
34

Perlu dicatat bahwa dukungan PHP 7 untuk kelas anonim telah ditambahkan. Ini memberi Anda jalan tambahan untuk menyiapkan tes untuk kelas abstrak, yang tidak bergantung pada fungsionalitas spesifik 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
}
GordonM
sumber
4
Terima kasih untuk ini! Menggunakan kelas anonim di PHPUnit memberi saya banyak fleksibilitas dalam membuat berbagai tes.
Alice Wonder
1

Eran, metode Anda harus bekerja, tetapi itu bertentangan dengan kecenderungan menulis tes sebelum kode aktual.

Apa yang saya sarankan adalah menulis tes Anda pada fungsionalitas yang diinginkan dari subkelas non-abstrak dari kelas abstrak yang dimaksud, kemudian menulis baik kelas abstrak dan subkelas pelaksana, dan akhirnya menjalankan tes.

Tes Anda jelas harus menguji metode yang didefinisikan dari kelas abstrak, tetapi selalu melalui subkelas.


sumber
Saya menemukan jawaban sewenang-wenang: Anda memiliki kelas abstrak 'A' yang memiliki metode 'foo ()' yang umum. Metode 'foo ()' ini digunakan secara keseluruhan semua kelas 'B', dan 'C', keduanya berasal dari 'A'. Kelas mana yang akan Anda pilih untuk menguji 'foo ()'?
user3790897
1

Jawaban Nelson salah.

Kelas abstrak tidak mengharuskan semua metode mereka abstrak.

Metode yang diterapkan adalah yang perlu kita uji.

Apa yang dapat Anda lakukan adalah membuat kelas rintisan palsu pada file unit test, minta itu memperluas kelas abstrak dan hanya menerapkan apa yang diperlukan tanpa fungsi sama sekali, tentu saja, dan mengujinya.

Bersulang.

skqr
sumber
0

Jika Anda tidak ingin subkelas kelas abstrak hanya untuk melakukan tes unit pada metode yang sudah diterapkan dalam kelas abstrak, Anda bisa mencoba melihat apakah kerangka kerja Anda memungkinkan Anda untuk mengejek kelas abstrak.

lengket
sumber