PHPUnit का दावा है कि एक अपवाद फेंक दिया गया था?


337

क्या किसी को पता है कि क्या ऐसा assertकुछ है या नहीं जो परीक्षण कर सकता है कि क्या एक अपवाद को परीक्षण किए गए कोड में फेंक दिया गया था?


2
उन जवाबों के लिए: एक परीक्षण समारोह में बहु-अभिकथन के बारे में क्या है, और मुझे सिर्फ एक फेंक अपवाद की उम्मीद है? क्या मुझे उन्हें अलग करना है और एक स्वतंत्र परीक्षण समारोह में रखना है?
पानवेन वांग

जवाबों:


549
<?php
require_once 'PHPUnit/Framework.php';

class ExceptionTest extends PHPUnit_Framework_TestCase
{
    public function 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);
    }
}

अपेक्षित अपवाद () PHPUnit प्रलेखन

PHPUnit लेखक लेख अपवाद सर्वोत्तम प्रथाओं के परीक्षण पर विस्तृत विवरण प्रदान करता है।


8
यदि आप नेमस्पेस का उपयोग करते हैं, तो आपको पूर्ण नामस्थान में प्रवेश करने की आवश्यकता है:$this->setExpectedException('\My\Name\Space\MyCustomException');
Alcalyn

15
तथ्य यह है कि आप कोड की सटीक रेखा को निर्दिष्ट नहीं कर सकते हैं जिसे फेंकने की उम्मीद है, एक त्रुटि आईएमओ है। और एक ही परीक्षण में एक से अधिक अपवाद के लिए परीक्षण करने में असमर्थता, कई अपेक्षित अपवादों के लिए परीक्षण करना वास्तव में एक भद्दा मामला है। मैंने लिखा ए उन समस्याओं को हल करने का प्रयास करने के लिए वास्तविक अभिकथन
mindplay.dk

18
FYI करें: जैसे कि phpunit 5.2.0 setExpectedException विधि को पदावनत किया जाता है, expectExceptionएक के साथ बदल दिया जाता है । :)
हज्जाद

41
डॉक्स या यहाँ उल्लेख नहीं किया गया है, लेकिन एक अपवाद को फेंकने के लिए अपेक्षित कोड को बाद में बुलाया जाना चाहिए expectException()। हालांकि यह कुछ के लिए स्पष्ट हो सकता था, यह मेरे लिए एक गोच था ।
जेसन मैककरी

7
यह डॉक्टर से स्पष्ट नहीं है, लेकिन आपके फ़ंक्शन के बाद कोई भी कोड जो अपवाद को नहीं फेंकता है उसे निष्पादित किया जाएगा। इसलिए यदि आप एक ही परीक्षण मामले में कई अपवादों का परीक्षण करना चाहते हैं तो आप नहीं कर सकते।
लौरेंत

122

PHPUnit 9 जारी होने तक आप एक डॉकब्लॉक एनोटेशन का भी उपयोग कर सकते हैं :

class ExceptionTest extends PHPUnit_Framework_TestCase
{
    /**
     * @expectedException InvalidArgumentException
     */
    public function testException()
    {
        ...
    }
}

PHP 5.5+ के लिए (विशेष रूप से नामांकित कोड के साथ), मैं अब उपयोग करना पसंद करता हूं ::class


3
IMO, यह पसंदीदा तरीका है।
माइक पर्सल

12
@LeviMorrison - IMHO अपवाद संदेश का परीक्षण नहीं किया जाना चाहिए, इसी तरह लॉग संदेश। मैनुअल फोरेंसिक करते समय दोनों को बाहरी, उपयोगी जानकारी माना जाता है । परीक्षण के लिए महत्वपूर्ण बिंदु अपवाद का प्रकार है। इससे परे कुछ भी कार्यान्वयन के लिए बहुत कसकर बाध्यकारी है। IncorrectPasswordExceptionपर्याप्त होना चाहिए - कि संदेश बराबर होता "Wrong password for bob@me.com"है। इसमें जोड़ें कि आप यथासंभव कम समय परीक्षण लिखने में खर्च करना चाहते हैं, और आप देखना शुरू करते हैं कि सरल परीक्षण कैसे महत्वपूर्ण हो जाते हैं।
डेविड हार्कस

5
@DavidHarkness मुझे लगा कि कोई इसे लाएगा। इसी तरह मैं सहमत हूं कि सामान्य रूप से परीक्षण संदेश बहुत सख्त और कड़े हैं। हालाँकि यह है कि सख्ती और चुस्त बाइंडिंग जो (उद्देश्यपूर्ण रूप से जोर दिया गया हो ) हो सकता है कि कुछ स्थितियों में क्या चाहिए, जैसे किसी कल्पना का प्रवर्तन।
लेवी मॉरिसन

1
मैं एक डॉक-ब्लॉक में यह समझने की कोशिश नहीं करूंगा कि यह क्या है, लेकिन मैं वास्तविक परीक्षा कोड (चाहे परीक्षण की तरह) को देखूंगा। यह अन्य सभी परीक्षणों के लिए मानक है; मुझे इस सम्मेलन के अपवाद होने के अपवादों के वैध कारण नहीं दिख रहे हैं ।
कामाफेदर

3
"संदेश का परीक्षण न करें" नियम मान्य लगता है, जब तक कि आप एक विधि का परीक्षण नहीं करते हैं जो कोड के कई हिस्सों में समान अपवाद प्रकार फेंकता है, एकमात्र अंतर त्रुटि आईडी के साथ होता है, जो संदेश में पारित हो जाता है। आपका सिस्टम अपवाद संदेश (अपवाद प्रकार नहीं) के आधार पर उपयोगकर्ता को एक संदेश प्रदर्शित कर सकता है। उस स्थिति में, यह मायने रखता है कि उपयोगकर्ता कौन सा संदेश देखता है, इसलिए, आपको त्रुटि संदेश का परीक्षण करना चाहिए।
वंजा डी।

34

यदि आप PHP 5.5+ पर चल रहे हैं, तो आप / के साथ वर्ग का नाम प्राप्त करने के लिए ::classरिज़ॉल्यूशन का उपयोग कर सकते हैं । इससे कई लाभ मिलते हैं:expectExceptionsetExpectedException

  • नाम अपने नाम स्थान (यदि कोई हो) के साथ पूरी तरह से योग्य होगा।
  • यह रिज़ॉल्यूशन करता है stringइसलिए यह PHPUnit के किसी भी संस्करण के साथ काम करेगा।
  • आपको अपने IDE में कोड-पूर्ति मिलती है।
  • यदि आप वर्ग के नाम को गलत समझते हैं तो PHP संकलक एक त्रुटि का उत्सर्जन करेगा।

उदाहरण:

namespace \My\Cool\Package;

class AuthTest extends \PHPUnit_Framework_TestCase
{
    public function testLoginFailsForWrongPassword()
    {
        $this->expectException(WrongPasswordException::class);
        Auth::login('Bob', 'wrong');
    }
}

PHP संकलन करता है

WrongPasswordException::class

में

"\My\Cool\Package\WrongPasswordException"

PHPUnit समझदार होने के बिना।

नोट : PHPUnit 5.2 expectException को एक प्रतिस्थापन के रूप में पेश किया गया है setExpectedException


32

नीचे दिए गए कोड अपवाद संदेश और अपवाद कोड का परीक्षण करेंगे।

महत्वपूर्ण: यह असफल होगा यदि अपेक्षित अपवाद भी नहीं फेंका गया।

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

6
$this->fail()इस तरह से इस्तेमाल करने का मतलब यह नहीं है कि मुझे नहीं लगता, कम से कम वर्तमान में नहीं (PHPUnit 3.6.11); यह एक अपवाद के रूप में कार्य करता है। अपने उदाहरण का उपयोग करना, अगर $this->fail("Expected exception not thrown")कहा जाता है, तो catchब्लॉक शुरू हो रहा है और $e->getMessage()है "अपवाद उत्पन्न नहीं की उम्मीद"
केन

1
@ आप शायद सही हैं। कॉल failसंभवतः ब्लॉक के बाद होता है, कोशिश के अंदर नहीं।
फ्रैंक किसान

1
मुझे नीचा failदिखाना होगा क्योंकि कॉल tryब्लॉक में नहीं होनी चाहिए । यह अपने आप में catchगलत परिणाम पैदा करने वाले ब्लॉक को ट्रिगर करता है ।
ट्विफ्टी

6
मेरा मानना ​​है कि यह अच्छी तरह से काम नहीं करता है कारण यह है कि यह कुछ अपवादों को झेल रहा है catch(Exception $e)। जब मैं विशिष्ट अपवादों को पकड़ने की कोशिश करता हूं तो यह विधि मेरे लिए काफी try { throw new MySpecificException; $this->fail('MySpecificException not thrown'); } catch(MySpecificException $e){}
कारगर साबित होती है

23

आप assertException एक्सटेंशन का उपयोग कर सकते हैं एक परीक्षण निष्पादन के दौरान एक से अधिक अपवादों का दावा करने के का ।

अपने TestCase में विधि डालें और उपयोग करें:

public function testSomething()
{
    $test = function() {
        // some code that has to throw an exception
    };
    $this->assertException( $test, 'InvalidArgumentException', 100, 'expected message' );
}

मैंने अच्छे कोड के प्रेमियों के लिए एक विशेषता भी बनाई है ।


आप किस PHPUnit का उपयोग कर रहे हैं? मैं PHPUnit 4.7.5 का उपयोग कर रहा हूं, और वहां assertExceptionपरिभाषित नहीं है। मैं इसे PHPUnit मैनुअल में भी नहीं ढूँढ सकता।
physicalattraction

2
asertExceptionविधि मूल PHPUnit का हिस्सा नहीं है। आपको PHPUnit_Framework_TestCaseक्लास को इनहेरिट करना होगा और मैन्युअल रूप से ऊपर पोस्ट में लिंक किया हुआ तरीका जोड़ना होगा । आपके परीक्षण के मामले तब इस विरासत वाले वर्ग को प्राप्त होंगे।
हेजदव

18

एक वैकल्पिक तरीका निम्नलिखित हो सकता है:

$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected Exception Message');

कृपया सुनिश्चित करें कि आपकी परीक्षा की कक्षा बढ़ रही है \PHPUnit_Framework_TestCase


इस वाक्य रचना में सबसे अधिक चीनी सुनिश्चित करने के लिए
एंड्रयूमैक्लागन

13

PHPUnit expectExceptionविधि बहुत असुविधाजनक है क्योंकि यह परीक्षण पद्धति के अनुसार केवल एक अपवाद का परीक्षण करने की अनुमति देता है।

मैंने इस सहायक समारोह को मुखर करने के लिए बनाया है कि कुछ फ़ंक्शन एक अपवाद फेंकता है:

/**
 * 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
 */
protected function 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');
}

इसे अपने परीक्षण वर्ग में जोड़ें और इस तरह से कॉल करें:

public function testSomething() {
    $this->assertException(\PDOException::class, function() {
        new \PDO('bad:param');
    });
    $this->assertException(\PDOException::class, function() {
        new \PDO('foo:bar');
    });
}

निश्चित रूप से सभी उत्तरों में से सबसे अच्छा समाधान! इसे एक विशेषता में फेंक दें और इसे पैकेज करें!
डोमडम्ब्रोगिया

11

व्यापक समाधान

अपवाद परीक्षण के लिए PHPUnit का वर्तमान " सर्वोत्तम अभ्यास " लगता है। अभाव ( डॉक्स )।

चूंकि मैं वर्तमान कार्यान्वयन से अधिक चाहता थाexpectException , इसलिए मैंने अपने परीक्षण मामलों पर उपयोग करने के लिए एक विशेषता बनाई। यह केवल ~ 50 लाइनों का कोड है

  • प्रति परीक्षण कई अपवादों का समर्थन करता है
  • अपवाद के बाद कहे जाने वाले कथनों का समर्थन करता है
  • मजबूत और स्पष्ट उपयोग उदाहरण
  • मानक assertवाक्यविन्यास
  • केवल संदेश, कोड और वर्ग से अधिक के लिए अभिकथन का समर्थन करता है
  • व्युत्क्रम का समर्थन करता है, assertNotThrows
  • PHP 7 Throwableत्रुटियों का समर्थन करता है

पुस्तकालय

मैंने गितुबAssertThrows और पैकैगिस्ट को विशेषता प्रकाशित की ताकि इसे संगीतकार के साथ स्थापित किया जा सके।

सरल उदाहरण

सिंटैक्स के पीछे की भावना को स्पष्ट करने के लिए:

<?php

// Using simple callback
$this->assertThrows(MyException::class, [$obj, 'doSomethingBad']);

// Using anonymous function
$this->assertThrows(MyException::class, function() use ($obj) {
    $obj->doSomethingBad();
});

काफी साफ़?


पूर्ण उपयोग उदाहरण

अधिक व्यापक उपयोग उदाहरण के लिए कृपया नीचे देखें:

<?php

declare(strict_types=1);

use Jchook\AssertThrows\AssertThrows;
use PHPUnit\Framework\TestCase;

// These are just for illustration
use MyNamespace\MyException;
use MyNamespace\MyObject;

final class MyTest extends TestCase
{
    use AssertThrows; // <--- adds the assertThrows method

    public function testMyObject()
    {
        $obj = new MyObject();

        // 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();
        });
    }
}

?>

4
थोड़ा विडंबना यह है कि यूनिट परीक्षण के लिए आपके पैकेज में रेपो में यूनिट परीक्षण शामिल नहीं हैं।
डोमडम्ब्रोगिया

2
@domdambrogia @ jean-beguin की बदौलत अब इसका यूनिट परीक्षण हुआ है।
19

8
public function testException() {
    try {
        $this->methodThatThrowsException();
        $this->fail("Expected Exception has not been raised.");
    } catch (Exception $ex) {
        $this->assertEquals($ex->getMessage(), "Exception message");
    }

}

के हस्ताक्षर assertEquals()है assertEquals(mixed $expected, mixed $actual...), अपने उदाहरण के रूप में, रिवर्स तो यह होना चाहिए$this->assertEquals("Exception message", $ex->getMessage());
रोजर Campanera

7

यहां सभी अपवाद दावे हैं जो आप कर सकते हैं। ध्यान दें कि वे सभी हैं वैकल्पिक हैं

class ExceptionTest extends PHPUnit_Framework_TestCase
{
    public function testException()
    {
        // make your exception assertions
        $this->expectException(InvalidArgumentException::class);
        // if you use namespaces:
        // $this->expectException('\Namespace\MyExceptio‌​n');
        $this->expectExceptionMessage('message');
        $this->expectExceptionMessageRegExp('/essage$/');
        $this->expectExceptionCode(123);
        // code that throws an exception
        throw new InvalidArgumentException('message', 123);
   }

   public function testAnotherException()
   {
        // repeat as needed
        $this->expectException(Exception::class);
        throw new Exception('Oh no!');
    }
}

प्रलेखन यहाँ पाया जा सकता है


यह गलत है क्योंकि PHP पहले फेंके गए अपवाद पर रुक जाता है। PHPUnit जाँच करता है कि फेंके गए अपवाद का सही प्रकार है और कहते हैं कि «परीक्षण ठीक है», यह दूसरे अपवाद के बारे में भी नहीं जानता है।
चालाकी

3
/**
 * @expectedException Exception
 * @expectedExceptionMessage Amount has to be bigger then 0!
 */
public function testDepositNegative()
{
    $this->account->deposit(-7);
}

बहुत लापरवाह रहें "/**", डबल "*" पर ध्यान दें। केवल "**" (तारांकन) लिखना आपके कोड को विफल कर देगा। यह भी सुनिश्चित करें कि आपका अंतिम संस्करण phpUnit का उपयोग कर रहा है। Phpunit के कुछ पुराने संस्करणों में @ अप्रत्याशित अपवाद अपवाद समर्थित नहीं है। मेरे पास 4.0 था और यह मेरे लिए काम नहीं करता था, मुझे संगीतकार के साथ अपडेट करने के लिए 5.5 https://coderwall.com/p/mklvdw/install-phpunit-with-composer पर अपडेट करना पड़ा ।


0

PHPUnit 5.7.27 और PHP 5.6 के लिए और एक परीक्षण में कई अपवादों का परीक्षण करने के लिए, अपवाद परीक्षण को मजबूर करना महत्वपूर्ण था। अपवाद का दावा करने के लिए अकेले अपवाद का उपयोग करना अपवाद नहीं होने पर स्थिति का परीक्षण करना छोड़ देगा।

public function testSomeFunction() {

    $e=null;
    $targetClassObj= new TargetClass();
    try {
        $targetClassObj->doSomething();
    } catch ( \Exception $e ) {
    }
    $this->assertInstanceOf(\Exception::class,$e);
    $this->assertEquals('Some message',$e->getMessage());

    $e=null;
    try {
        $targetClassObj->doSomethingElse();
    } catch ( Exception $e ) {
    }
    $this->assertInstanceOf(\Exception::class,$e);
    $this->assertEquals('Another message',$e->getMessage());

}

0
function yourfunction($a,$z){
   if($a<$z){ throw new <YOUR_EXCEPTION>; }
}

यहाँ परीक्षण है

class FunctionTest extends \PHPUnit_Framework_TestCase{

   public function testException(){

      $this->setExpectedException(<YOUR_EXCEPTION>::class);
      yourfunction(1,2);//add vars that cause the exception 

   }

}

0

PhpUnit एक अद्भुत पुस्तकालय है, लेकिन यह विशिष्ट बिंदु थोड़ा निराशाजनक है। यही कारण है कि हम टर्बोटिंग-पीएचपी ओपनसोर्स लाइब्रेरी का उपयोग कर सकते हैं, जिसमें अपवादों के परीक्षण में मदद करने के लिए एक बहुत ही सुविधाजनक शोध पद्धति है। यह यहाँ पाया जाता है:

https://github.com/edertone/TurboTesting/blob/master/TurboTesting-Php/src/main/php/utils/AssertUtils.php

और इसका उपयोग करने के लिए, हम बस निम्नलिखित करेंगे:

AssertUtils::throwsException(function(){

    // Some code that must throw an exception here

}, '/expected error message/');

अनाम फ़ंक्शन के अंदर हम जो कोड टाइप करते हैं, यदि वह अपवाद नहीं छोड़ता है, तो एक अपवाद फेंक दिया जाएगा।

यदि हम अनाम फ़ंक्शन के अंदर जो कोड टाइप करते हैं वह एक अपवाद को फेंक देता है, लेकिन इसका संदेश अपेक्षित रीजैक्स से मेल नहीं खाता है, एक अपवाद भी फेंक दिया जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.