Untuk jawaban-jawaban itu: bagaimana dengan multi-pernyataan dalam suatu fungsi tes, dan saya hanya berharap untuk memiliki satu pengecualian melempar? Apakah saya HARUS memisahkannya dan meletakkannya dalam fungsi tes independen?
Panwen Wang
Jawaban:
550
<?php
require_once 'PHPUnit/Framework.php';classExceptionTestextendsPHPUnit_Framework_TestCase{publicfunction testException(){
$this->expectException(InvalidArgumentException::class);// or for PHPUnit < 5.2// $this->setExpectedException(InvalidArgumentException::class);//...and then add your test code that generates the exception
exampleMethod($anInvalidArgument);}}
Jika Anda menggunakan namespaces, Anda harus memasukkan namespace lengkap:$this->setExpectedException('\My\Name\Space\MyCustomException');
Alcalyn
15
Fakta bahwa Anda tidak dapat menentukan baris kode yang tepat yang diharapkan untuk dibuang, adalah IMO galat. Dan ketidakmampuan untuk menguji lebih dari satu pengecualian dalam pengujian yang sama, membuat pengujian untuk banyak pengecualian yang diharapkan benar-benar kikuk. Saya menulis pernyataan yang sebenarnya untuk mencoba menyelesaikan masalah-masalah itu.
mindplay.dk
18
FYI: pada metode phpunit 5.2.0setExpectedException sudah usang, diganti dengan yang expectExceptionsatu. :)
hejdav
41
Apa yang tidak disebutkan dalam dokumen atau di sini, tapi kode diharapkan untuk melemparkan pengecualian kebutuhan untuk dipanggil setelahexpectException() . Sementara itu mungkin sudah jelas untuk beberapa, itu adalah Gotcha bagi saya.
Jason McCreary
7
Tidak jelas dari dokumen, tetapi tidak ada kode setelah fungsi Anda yang melempar pengecualian akan dieksekusi. Jadi, jika Anda ingin menguji beberapa pengecualian dalam test case yang sama, Anda tidak bisa.
laurent
122
Anda juga dapat menggunakan anotasi docblock hingga PHPUnit 9 dirilis:
@LeviMorrison - IMHO pesan pengecualian tidak boleh diuji, mirip dengan pesan log. Keduanya dianggap sebagai informasi asing yang membantu ketika melakukan forensik manual . Titik kunci untuk menguji adalah jenis pengecualian. Apa pun di luar itu mengikat terlalu ketat pada implementasinya. IncorrectPasswordExceptionharus cukup - bahwa pesan yang sama "Wrong password for [email protected]"adalah tambahan. Tambahkan bahwa Anda ingin menghabiskan sedikit waktu menulis tes mungkin, dan Anda mulai melihat betapa pentingnya tes sederhana menjadi.
David Harkness
5
@ Davidvidark, saya pikir seseorang akan mengungkitnya. Saya juga akan setuju bahwa pengujian pesan secara umum terlalu ketat dan ketat. Namun, keketatan dan pengikatan ketat itulah yang mungkin (ditekankan dengan sengaja) seperti yang diinginkan dalam beberapa situasi, seperti penegakan suatu spec.
Levi Morrison
1
Saya tidak akan menonton di blok dokumen untuk memahami apa yang diharapkan, tetapi saya akan melihat kode tes yang sebenarnya (terlepas dari jenis tes). Itu standar untuk semua tes lainnya; Saya tidak melihat alasan yang sah untuk Pengecualian sebagai (oh tuhan) pengecualian untuk konvensi ini.
Kamafeather
3
Aturan "jangan menguji pesan" terdengar valid, kecuali jika Anda menguji metode yang melempar tipe pengecualian yang sama di beberapa bagian kode, dengan satu-satunya perbedaan adalah id kesalahan, yang diteruskan dalam pesan. Sistem Anda mungkin menampilkan pesan kepada pengguna berdasarkan pesan Pengecualian (bukan tipe Pengecualian). Dalam hal itu, tidak masalah pesan mana yang dilihat pengguna, oleh karena itu, Anda harus menguji pesan kesalahan tersebut.
Kode di bawah ini akan menguji pesan pengecualian dan kode pengecualian.
Penting: Ini akan gagal jika pengecualian yang diharapkan tidak dibuang juga.
try{
$test->methodWhichWillThrowException();//if this method not throw exception it must be fail too.
$this->fail("Expected exception 1162011 not thrown");}catch(MySpecificException $e){//Not catching a generic Exception or the fail function is also catched
$this->assertEquals(1162011, $e->getCode());
$this->assertEquals("Exception Message", $e->getMessage());}
$this->fail()tidak dimaksudkan untuk digunakan dengan cara ini saya tidak berpikir, setidaknya saat ini (PHPUnit 3.6.11); itu bertindak sebagai pengecualian itu sendiri. Menggunakan contoh, jika $this->fail("Expected exception not thrown")disebut, maka catchblok dipicu dan $e->getMessage()yang "diharapkan pengecualian tidak dilempar" .
ken
1
@ken Anda mungkin benar. Panggilan ke failmungkin milik setelah blok tangkap, bukan di dalam coba.
Frank Farmer
1
Saya harus downvote karena panggilan ke failtidak boleh di tryblok. Itu sendiri memicu catchblok menghasilkan hasil yang salah.
Twifty
6
Saya percaya alasan ini tidak bekerja dengan baik adalah beberapa situasi adalah bahwa itu menangkap semua pengecualian catch(Exception $e). Metode ini bekerja cukup baik untuk saya ketika saya mencoba menangkap Pengecualian tertentu:try { throw new MySpecificException; $this->fail('MySpecificException not thrown'); } catch(MySpecificException $e){}
spyle
23
Anda dapat menggunakan ekstensi assertException untuk menegaskan lebih dari satu pengecualian selama satu pengujian dijalankan.
Masukkan metode ke dalam TestCase Anda dan gunakan:
publicfunction testSomething(){
$test =function(){// some code that has to throw an exception};
$this->assertException( $test,'InvalidArgumentException',100,'expected message');}
Saya juga membuat sifat untuk pecinta kode yang bagus ..
PHPUnit mana yang Anda gunakan? Saya menggunakan PHPUnit 4.7.5, dan tidak ada assertExceptiondefinisi. Saya juga tidak dapat menemukannya di manual PHPUnit.
physicalattraction
2
The asertExceptionMetode bukan bagian dari PHPUnit asli. Anda harus mewarisi PHPUnit_Framework_TestCasekelas dan menambahkan metode yang ditautkan dalam posting di atas secara manual. Kasing uji Anda akan mewarisi kelas warisan ini.
expectExceptionMetode PHPUnit sangat merepotkan karena memungkinkan untuk menguji hanya satu pengecualian per metode pengujian.
Saya telah membuat fungsi pembantu ini untuk menyatakan bahwa beberapa fungsi melempar pengecualian:
/**
* Asserts that the given callback throws the given exception.
*
* @param string $expectClass The name of the expected exception class
* @param callable $callback A callback which should throw the exception
*/protectedfunction assertException(string $expectClass, callable $callback){try{
$callback();}catch(\Throwable $exception){
$this->assertInstanceOf($expectClass, $exception,'An invalid exception was thrown');return;}
$this->fail('No exception was thrown');}
Tambahkan ke kelas tes Anda dan panggil seperti ini:
Pasti solusi terbaik dari semua jawaban! Membuangnya ke dalam sifat dan mengemasnya!
domdambrogia
11
Solusi Komprehensif
" Praktik terbaik " PHPUnit saat ini untuk pengujian pengecualian tampaknya .. kurang bersemangat ( dokumen ).
Karena saya menginginkan lebih dari expectExceptionimplementasi saat ini , saya membuat sifat untuk digunakan pada kasus pengujian saya. Hanya ~ 50 baris kode .
Mendukung banyak pengecualian per tes
Mendukung pernyataan yang dipanggil setelah pengecualian dilemparkan
Contoh penggunaan yang kuat dan jelas
assertSintaks standar
Mendukung pernyataan untuk lebih dari sekadar pesan, kode, dan kelas
Mendukung pernyataan terbalik, assertNotThrows
Mendukung Throwablekesalahan PHP 7
Perpustakaan
Saya menerbitkan AssertThrowssifat tersebut ke Github dan pembuat kemasan sehingga dapat diinstal dengan komposer.
Contoh sederhana
Hanya untuk menggambarkan semangat di balik sintaks:
<?php
// Using simple callback
$this->assertThrows(MyException::class,[$obj,'doSomethingBad']);// Using anonymous function
$this->assertThrows(MyException::class,function()use($obj){
$obj->doSomethingBad();});
Cukup rapi?
Contoh Penggunaan Lengkap
Silakan lihat di bawah untuk contoh penggunaan yang lebih komprehensif:
<?php
declare(strict_types=1);useJchook\AssertThrows\AssertThrows;usePHPUnit\Framework\TestCase;// These are just for illustrationuseMyNamespace\MyException;useMyNamespace\MyObject;finalclassMyTestextendsTestCase{useAssertThrows;// <--- adds the assertThrows methodpublicfunction testMyObject(){
$obj =newMyObject();// Test a basic exception is thrown
$this->assertThrows(MyException::class,function()use($obj){
$obj->doSomethingBad();});// Test custom aspects of a custom extension class
$this->assertThrows(MyException::class,function()use($obj){
$obj->doSomethingBad();},function($exception){
$this->assertEquals('Expected value', $exception->getCustomThing());
$this->assertEquals(123, $exception->getCode());});// Test that a specific exception is NOT thrown
$this->assertNotThrows(MyException::class,function()use($obj){
$obj->doSomethingGood();});}}?>
Agak ironis bahwa paket Anda untuk pengujian unit tidak termasuk tes unit dalam repo.
domdambrogia
2
@domdambrogia berkat @ jean-beguin sekarang memiliki unit test.
jchook
8
publicfunction testException(){try{
$this->methodThatThrowsException();
$this->fail("Expected Exception has not been raised.");}catch(Exception $ex){
$this->assertEquals($ex->getMessage(),"Exception message");}}
Tanda tangan dari assertEquals()adalah assertEquals(mixed $expected, mixed $actual...), terbalik seperti pada contoh Anda, jadi seharusnya$this->assertEquals("Exception message", $ex->getMessage());
Roger Campanera
7
Berikut semua pernyataan pengecualian yang dapat Anda lakukan. Perhatikan bahwa semuanya adalah opsional .
classExceptionTestextendsPHPUnit_Framework_TestCase{publicfunction testException(){// make your exception assertions
$this->expectException(InvalidArgumentException::class);// if you use namespaces:// $this->expectException('\Namespace\MyException');
$this->expectExceptionMessage('message');
$this->expectExceptionMessageRegExp('/essage$/');
$this->expectExceptionCode(123);// code that throws an exceptionthrownewInvalidArgumentException('message',123);}publicfunction testAnotherException(){// repeat as needed
$this->expectException(Exception::class);thrownewException('Oh no!');}}
Itu salah karena PHP berhenti pada pengecualian yang pertama kali dilempar. PHPUnit memeriksa bahwa eksepsi yang dilempar memiliki tipe yang benar dan mengatakan «tesnya OK», bahkan tidak tahu tentang eksepsi kedua.
Finesse
3
/**
* @expectedException Exception
* @expectedExceptionMessage Amount has to be bigger then 0!
*/publicfunction testDepositNegative(){
$this->account->deposit(-7);}
Berhati-hatilah "/**", perhatikan ganda "*". Hanya menulis "**" (asterix) yang akan gagal kode Anda. Pastikan juga Anda menggunakan versi terakhir phpUnit. Dalam beberapa versi sebelumnya, phpunit @expectedException Exception tidak didukung. Saya memiliki 4.0 dan tidak berfungsi untuk saya, saya harus memperbarui ke 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer untuk memperbarui dengan komposer.
Untuk PHPUnit 5.7.27 dan PHP 5.6 dan untuk menguji beberapa pengecualian dalam satu pengujian, penting untuk memaksa pengujian pengecualian. Menggunakan penanganan pengecualian saja untuk menegaskan instance Exception akan melewatkan pengujian situasi jika tidak ada pengecualian yang terjadi.
function yourfunction($a,$z){if($a<$z){thrownew<YOUR_EXCEPTION>;}}
ini tesnya
classFunctionTestextends \PHPUnit_Framework_TestCase{publicfunction testException(){
$this->setExpectedException(<YOUR_EXCEPTION>::class);
yourfunction(1,2);//add vars that cause the exception }}
PhpUnit adalah perpustakaan yang luar biasa, tetapi poin khusus ini agak membuat frustrasi. Inilah sebabnya kami dapat menggunakan pustaka opensource php-turbotesting yang memiliki metode pernyataan yang sangat nyaman untuk membantu kami menguji pengecualian. Itu ditemukan di sini:
Dan untuk menggunakannya, kita cukup melakukan hal berikut:
AssertUtils::throwsException(function(){// Some code that must throw an exception here},'/expected error message/');
Jika kode yang kita ketikkan di dalam fungsi anonim tidak memunculkan eksepsi, eksepsi akan dilempar.
Jika kode yang kita ketikkan di dalam fungsi anonim melempar pengecualian, tetapi pesannya tidak cocok dengan regexp yang diharapkan, pengecualian juga akan dibuang.
Jawaban:
expectException () dokumentasi PHPUnit
Artikel penulis PHPUnit memberikan penjelasan terperinci tentang pengujian pengecualian praktik terbaik.
sumber
$this->setExpectedException('\My\Name\Space\MyCustomException');
setExpectedException
sudah usang, diganti dengan yangexpectException
satu. :)expectException()
. Sementara itu mungkin sudah jelas untuk beberapa, itu adalah Gotcha bagi saya.Anda juga dapat menggunakan anotasi docblock hingga PHPUnit 9 dirilis:
Untuk PHP 5.5+ (terutama dengan kode namespaced), saya sekarang lebih suka menggunakan
::class
sumber
IncorrectPasswordException
harus cukup - bahwa pesan yang sama"Wrong password for [email protected]"
adalah tambahan. Tambahkan bahwa Anda ingin menghabiskan sedikit waktu menulis tes mungkin, dan Anda mulai melihat betapa pentingnya tes sederhana menjadi.Jika Anda menggunakan PHP 5.5+, Anda bisa menggunakan
::class
resolusi untuk mendapatkan nama kelas denganexpectException
/setExpectedException
. Ini memberikan beberapa manfaat:string
jadi itu akan bekerja dengan versi PHPUnit.Contoh:
Kompilasi PHP
ke
tanpa PHPUnit menjadi lebih bijak.
sumber
Kode di bawah ini akan menguji pesan pengecualian dan kode pengecualian.
Penting: Ini akan gagal jika pengecualian yang diharapkan tidak dibuang juga.
sumber
$this->fail()
tidak dimaksudkan untuk digunakan dengan cara ini saya tidak berpikir, setidaknya saat ini (PHPUnit 3.6.11); itu bertindak sebagai pengecualian itu sendiri. Menggunakan contoh, jika$this->fail("Expected exception not thrown")
disebut, makacatch
blok dipicu dan$e->getMessage()
yang "diharapkan pengecualian tidak dilempar" .fail
mungkin milik setelah blok tangkap, bukan di dalam coba.fail
tidak boleh ditry
blok. Itu sendiri memicucatch
blok menghasilkan hasil yang salah.catch(Exception $e)
. Metode ini bekerja cukup baik untuk saya ketika saya mencoba menangkap Pengecualian tertentu:try { throw new MySpecificException; $this->fail('MySpecificException not thrown'); } catch(MySpecificException $e){}
Anda dapat menggunakan ekstensi assertException untuk menegaskan lebih dari satu pengecualian selama satu pengujian dijalankan.
Masukkan metode ke dalam TestCase Anda dan gunakan:
Saya juga membuat sifat untuk pecinta kode yang bagus ..
sumber
assertException
definisi. Saya juga tidak dapat menemukannya di manual PHPUnit.asertException
Metode bukan bagian dari PHPUnit asli. Anda harus mewarisiPHPUnit_Framework_TestCase
kelas dan menambahkan metode yang ditautkan dalam posting di atas secara manual. Kasing uji Anda akan mewarisi kelas warisan ini.Cara alternatif bisa sebagai berikut:
Harap pastikan bahwa kelas tes Anda meluas
\PHPUnit_Framework_TestCase
.sumber
expectException
Metode PHPUnit sangat merepotkan karena memungkinkan untuk menguji hanya satu pengecualian per metode pengujian.Saya telah membuat fungsi pembantu ini untuk menyatakan bahwa beberapa fungsi melempar pengecualian:
Tambahkan ke kelas tes Anda dan panggil seperti ini:
sumber
Solusi Komprehensif
" Praktik terbaik " PHPUnit saat ini untuk pengujian pengecualian tampaknya .. kurang bersemangat ( dokumen ).
Karena saya menginginkan lebih dari
expectException
implementasi saat ini , saya membuat sifat untuk digunakan pada kasus pengujian saya. Hanya ~ 50 baris kode .assert
Sintaks standarassertNotThrows
Throwable
kesalahan PHP 7Perpustakaan
Saya menerbitkan
AssertThrows
sifat tersebut ke Github dan pembuat kemasan sehingga dapat diinstal dengan komposer.Contoh sederhana
Hanya untuk menggambarkan semangat di balik sintaks:
Cukup rapi?
Contoh Penggunaan Lengkap
Silakan lihat di bawah untuk contoh penggunaan yang lebih komprehensif:
sumber
sumber
assertEquals()
adalahassertEquals(mixed $expected, mixed $actual...)
, terbalik seperti pada contoh Anda, jadi seharusnya$this->assertEquals("Exception message", $ex->getMessage());
Berikut semua pernyataan pengecualian yang dapat Anda lakukan. Perhatikan bahwa semuanya adalah opsional .
Dokumentasi dapat ditemukan di sini .
sumber
Berhati-hatilah
"/**"
, perhatikan ganda "*". Hanya menulis "**" (asterix) yang akan gagal kode Anda. Pastikan juga Anda menggunakan versi terakhir phpUnit. Dalam beberapa versi sebelumnya, phpunit @expectedException Exception tidak didukung. Saya memiliki 4.0 dan tidak berfungsi untuk saya, saya harus memperbarui ke 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer untuk memperbarui dengan komposer.sumber
Untuk PHPUnit 5.7.27 dan PHP 5.6 dan untuk menguji beberapa pengecualian dalam satu pengujian, penting untuk memaksa pengujian pengecualian. Menggunakan penanganan pengecualian saja untuk menegaskan instance Exception akan melewatkan pengujian situasi jika tidak ada pengecualian yang terjadi.
sumber
ini tesnya
sumber
PhpUnit adalah perpustakaan yang luar biasa, tetapi poin khusus ini agak membuat frustrasi. Inilah sebabnya kami dapat menggunakan pustaka opensource php-turbotesting yang memiliki metode pernyataan yang sangat nyaman untuk membantu kami menguji pengecualian. Itu ditemukan di sini:
https://github.com/edertone/TurboTesting/blob/master/TurboTesting-Php/src/main/php/utils/AssertUtils.php
Dan untuk menggunakannya, kita cukup melakukan hal berikut:
Jika kode yang kita ketikkan di dalam fungsi anonim tidak memunculkan eksepsi, eksepsi akan dilempar.
Jika kode yang kita ketikkan di dalam fungsi anonim melempar pengecualian, tetapi pesannya tidak cocok dengan regexp yang diharapkan, pengecualian juga akan dibuang.
sumber