परीक्षण हुक कॉलबैक


34

मैं TDD और एक चीज का उपयोग करके एक प्लगइन विकसित कर रहा हूं जिसे मैं पूरी तरह से परीक्षण करने में विफल हूं ... हुक।

मेरा मतलब है ठीक है, मैं हुक कॉलबैक का परीक्षण कर सकता हूं, लेकिन अगर हुक वास्तव में ट्रिगर (कस्टम हुक और वर्डप्रेस डिफ़ॉल्ट हुक) दोनों हो तो मैं कैसे परीक्षण कर सकता हूं? मुझे लगता है कि कुछ मज़ाक करने में मदद मिलेगी, लेकिन मैं बस यह पता नहीं लगा सकता कि मैं क्या याद कर रहा हूं।

मैंने WP-CLI के साथ परीक्षण सूट स्थापित किया। इस उत्तर के अनुसार , initहुक को ट्रिगर करना चाहिए, फिर भी ... यह नहीं है; इसके अलावा, वर्डप्रेस के अंदर कोड काम करता है।

मेरी समझ से, बूटस्ट्रैप अंतिम बार लोड किया गया है, इसलिए यह इनिट को ट्रिगर न करने के लिए समझ में आता है, इसलिए सवाल यह है कि: हुक का ट्रिगर होने पर हेक मुझे कैसे परीक्षण करना चाहिए?

धन्यवाद!

बूटस्ट्रैप फ़ाइल इस तरह दिखती है:

$_tests_dir = getenv('WP_TESTS_DIR');
if ( !$_tests_dir ) $_tests_dir = '/tmp/wordpress-tests-lib';

require_once $_tests_dir . '/includes/functions.php';

function _manually_load_plugin() {
  require dirname( __FILE__ ) . '/../includes/RegisterCustomPostType.php';
}
tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );

require $_tests_dir . '/includes/bootstrap.php';

परीक्षण फ़ाइल इस तरह दिखता है:

class RegisterCustomPostType {
  function __construct()
  {
    add_action( 'init', array( $this, 'register_post_type' ) );
  }

  public function register_post_type()
  {
    register_post_type( 'foo' );
  }
}

और परीक्षण ही:

class CustomPostTypes extends WP_UnitTestCase {
  function test_custom_post_type_creation()
  {
    $this->assertTrue( post_type_exists( 'foo' ) );
  }
}

धन्यवाद!


यदि आप दौड़ रहे हैं phpunit, तो क्या आप असफल या उत्तीर्ण परीक्षण देख सकते हैं? क्या आपने स्थापित किया bin/install-wp-tests.sh?
स्वेन

मुझे लगता है कि समस्या का हिस्सा यह है कि शायद RegisterCustomPostType::__construct()कभी नहीं कहा जाता है जब परीक्षणों के लिए प्लगइन लोड किया जाता है। यह भी संभव है कि आप बग # 29827 से प्रभावित हो रहे हों ; शायद WP के यूनिट टेस्ट सूट के अपने संस्करण को अपडेट करने का प्रयास करें।
जेडी

@ स्वेन: हाँ, परीक्षण विफल हो रहे हैं; मैंने स्थापित किया bin/install-wp-tests.sh(क्योंकि मैंने wp-cli का उपयोग किया था) @JD: RegisterCustomPostType :: __ कंस्ट्रक्शन को कहा जाता है (बस एक die()स्टेटमेंट जोड़ा जाता है और वहां phpunit बंद हो जाता है)
Ionut

मैं यूनिट परीक्षण पक्ष (मेरी बाइट नहीं) पर भी निश्चित नहीं हूं, लेकिन शाब्दिक दृष्टिकोण से आप यह did_action()जांचने के लिए उपयोग कर सकते हैं कि क्या कार्रवाई की गई थी।
रारस्ट

@ सार: सुझाव के लिए धन्यवाद, लेकिन यह अभी भी काम नहीं करता है। किसी कारण से, मुझे लगता है कि समय गलत है ( initहुक से पहले परीक्षण किए जाते हैं )।
इओनुत स्टैस्यू

जवाबों:


72

अलगाव में परीक्षण

एक प्लगइन विकसित करते समय, यह परीक्षण करने का सबसे अच्छा तरीका वर्डप्रेस पर्यावरण को लोड किए बिना है।

यदि आप ऐसे कोड लिखते हैं, जो वर्डप्रेस के बिना आसानी से जांचे जा सकते हैं, तो आपका कोड बेहतर हो जाता है

प्रत्येक घटक जो इकाई परीक्षण किया जाता है, उसे अलगाव में परीक्षण किया जाना चाहिए : जब आप एक वर्ग का परीक्षण करते हैं, तो आपको केवल उस विशिष्ट वर्ग का परीक्षण करना होगा, यह मानते हुए कि अन्य सभी कोड पूरी तरह से काम कर रहे हैं।

अलग करनेवाला

यही कारण है कि यूनिट परीक्षणों को "यूनिट" कहा जाता है।

एक अतिरिक्त लाभ के रूप में, लोडिंग कोर के बिना, आपका परीक्षण बहुत तेज़ी से चलेगा।

कंस्ट्रक्टर में हुक से बचें

एक टिप जो मैं आपको दे सकता हूं, वह है कंस्ट्रक्टरों में हुक लगाने से बचना। यह उन चीजों में से एक है जो आपके कोड को अलगाव में परीक्षण योग्य बना देगा।

आइए देखें ओपी में परीक्षण कोड:

class CustomPostTypes extends WP_UnitTestCase {
  function test_custom_post_type_creation() {
    $this->assertTrue( post_type_exists( 'foo' ) );
  }
}

और मान लेते हैं कि यह परीक्षा विफल हैअपराधी कौन है ?

  • हुक बिल्कुल नहीं जोड़ा गया था या ठीक से नहीं था?
  • विधि जो पोस्ट प्रकार को पंजीकृत करती है उसे बिल्कुल भी या गलत तर्कों के साथ नहीं बुलाया गया था?
  • वर्डप्रेस में बग है?

इसे कैसे सुधारा जा सकता है?

मान लें कि आपका वर्ग कोड है:

class RegisterCustomPostType {

  function init() {
    add_action( 'init', array( $this, 'register_post_type' ) );
  }

  public function register_post_type() {
    register_post_type( 'foo' );
  }
}

(नोट: मैं शेष उत्तर के लिए कक्षा के इस संस्करण का उल्लेख करूंगा)

जिस तरह से मैंने इस वर्ग को लिखा है वह आपको बिना बुलाए कक्षा के उदाहरण बनाने की अनुमति देता है add_action

ऊपर की कक्षा में 2 चीजों का परीक्षण किया जाना है:

  • विधि init वास्तव में कॉल add_actionकरने के लिए यह उचित तर्क है
  • विधि register_post_type वास्तव मेंregister_post_type फ़ंक्शन को कॉल करती है

मैंने यह नहीं कहा कि यदि पोस्ट प्रकार मौजूद है तो आपको जांचना होगा: यदि आप उचित कार्रवाई जोड़ते हैं और यदि आप कॉल करते हैं register_post_type, तो कस्टम पोस्ट प्रकार मौजूद होना चाहिए : यदि यह मौजूद नहीं है तो यह एक वर्डप्रेस समस्या है।

याद रखें: जब आप अपने प्लगइन का परीक्षण करते हैं तो आपको अपने कोड का परीक्षण करना होता है , न कि वर्डप्रेस कोड का। अपने परीक्षणों में आपको यह मान लेना है कि वर्डप्रेस (आपके द्वारा उपयोग की जाने वाली किसी अन्य बाहरी लाइब्रेरी की तरह) अच्छी तरह से काम करता है। यही इकाई परीक्षण का अर्थ है ।

लेकिन ... व्यवहार में?

यदि वर्डप्रेस लोड नहीं है, यदि आप ऊपर दिए गए क्लास के तरीकों को कॉल करने का प्रयास करते हैं, तो आपको एक घातक त्रुटि मिलती है, इसलिए आपको फ़ंक्शन को मॉक करने की आवश्यकता है।

"मैनुअल" विधि

सुनिश्चित करें कि आप अपनी मॉकिंग लाइब्रेरी या "मैन्युअल रूप से" प्रत्येक विधि का मजाक उड़ा सकते हैं। यह संभव है। मैं आपको बताऊंगा कि कैसे करना है, लेकिन फिर मैं आपको एक आसान तरीका दिखाऊंगा।

यदि परीक्षण चल रहे हैं, तो वर्डप्रेस लोड नहीं है, इसका मतलब है कि आप इसके कार्यों को फिर से परिभाषित कर सकते हैं, जैसे add_actionया register_post_type

मान लें कि आपके पास एक फ़ाइल है, जो आपके बूटस्ट्रैप फ़ाइल से भरी हुई है, जहाँ आपके पास है:

function add_action() {
  global $counter;
  if ( ! isset($counter['add_action']) ) {
    $counter['add_action'] = array();
  }
  $counter['add_action'][] = func_get_args();
}

function register_post_type() {
  global $counter;
  if ( ! isset($counter['register_post_type']) ) {
    $counter['register_post_type'] = array();
  }
  $counter['register_post_type'][] = func_get_args();
}

मैंने हर बार उन्हें एक वैश्विक सरणी में एक तत्व जोड़ने के लिए फ़ंक्शन को फिर से लिखा।

अब आपको (यदि आपके पास पहले से कोई नहीं है) अपना बेस टेस्ट केस क्लास बढ़ा देना चाहिए PHPUnit_Framework_TestCase : जो आपको आसानी से अपने टेस्ट को कॉन्फ़िगर करने की अनुमति देता है।

यह कुछ इस तरह हो सकता है:

class Custom_TestCase extends \PHPUnit_Framework_TestCase {

    public function setUp() {
        $GLOBALS['counter'] = array();
    }

}

इस तरह, प्रत्येक परीक्षण से पहले, वैश्विक काउंटर रीसेट हो जाता है।

और अब आपका परीक्षण कोड (मैं ऊपर पोस्ट किए गए पुनर्लेखन वर्ग को संदर्भित करता हूं):

class CustomPostTypes extends Custom_TestCase {

  function test_init() {
     global $counter;
     $r = new RegisterCustomPostType;
     $r->init();
     $this->assertSame(
       $counter['add_action'][0],
       array( 'init', array( $r, 'register_post_type' ) )
     );
  }

  function test_register_post_type() {
     global $counter;
     $r = new RegisterCustomPostType;
     $r->register_post_type();
     $this->assertSame( $counter['register_post_type'][0], array( 'foo' ) );
  }

}

आपको ध्यान देना चाहिए:

  • मैं दो तरीकों को अलग-अलग कॉल करने में सक्षम था और वर्डप्रेस बिल्कुल भी लोड नहीं है। इस तरह यदि एक भी परीक्षा विफल हो जाती है, तो मुझे पता है कि अपराधी कौन है।
  • जैसा कि मैंने कहा, यहाँ मैं परीक्षण करता हूँ कि वर्ग WP कार्यों को अपेक्षित तर्कों के साथ कहते हैं। अगर सीपीटी वास्तव में मौजूद है तो परीक्षण करने की कोई आवश्यकता नहीं है। यदि आप CPT के अस्तित्व का परीक्षण कर रहे हैं, तो आप वर्डप्रेस व्यवहार का परीक्षण कर रहे हैं, न कि आपके प्लगइन व्यवहार ...

अच्छा है .. लेकिन यह एक PITA है!

हां, यदि आपको सभी वर्डप्रेस फंक्शंस को मैन्युअल रूप से मॉक करना है, तो यह वास्तव में एक दर्द है। कुछ सामान्य सलाह जो मैं दे सकता हूं वह है कि कुछ WP फ़ंक्शन का उपयोग करें: आपको वर्डप्रेस को फिर से लिखना नहीं है , लेकिन अमूर्त WP फ़ंक्शंस आप कस्टम कक्षाओं में उपयोग करते हैं, ताकि उन्हें नकली और आसानी से परीक्षण किया जा सके।

उदाहरण के लिए ऊपर, आप एक वर्ग लिख सकते हैं जो पोस्ट प्रकार को पंजीकृत करता है, register_post_typeदिए गए तर्कों के साथ 'इनिट' पर कॉल करता है। इस अमूर्तता के साथ आपको अभी भी उस वर्ग का परीक्षण करने की आवश्यकता है, लेकिन आपके कोड के अन्य स्थानों में जो पोस्ट प्रकारों को पंजीकृत करते हैं, आप उस कक्षा का उपयोग कर सकते हैं, इसे परीक्षण में मॉकिंग कर सकते हैं (इसलिए यह काम करता है)।

कमाल की बात यह है, यदि आप CPT पंजीकरण को अमूर्त करने वाले वर्ग को लिखते हैं, तो आप इसके लिए एक अलग रिपॉजिटरी बना सकते हैं, और संगीतकार जैसे आधुनिक उपकरणों के लिए धन्यवाद, इसे उन सभी परियोजनाओं में एम्बेड करें जहाँ आपको इसकी आवश्यकता है: एक बार परीक्षण करें, हर जगह उपयोग करें । और यदि आपको कभी इसमें कोई बग दिखाई देता है, तो आप इसे एक स्थान पर ठीक कर सकते हैं और एक सरल composer updateसभी परियोजनाओं के साथ जहां इसका उपयोग किया जाता है, उसे भी ठीक किया जाता है।

दूसरी बार: कोड लिखने के लिए जो अलगाव में परीक्षण योग्य है का अर्थ है बेहतर कोड लिखना।

लेकिन जितनी जल्दी या बाद में मुझे कहीं न कहीं WP फ़ंक्शन का उपयोग करने की आवश्यकता है ...

बेशक। आपको कभी भी कोर के समानांतर कार्य नहीं करना चाहिए , इससे कोई मतलब नहीं है। आप WP फ़ंक्शन को लपेटने वाली कक्षाएं लिख सकते हैं, लेकिन उन कक्षाओं को भी जांचने की आवश्यकता है। ऊपर वर्णित "मैनुअल" विधि का उपयोग बहुत ही सरल कार्यों के लिए किया जा सकता है, लेकिन जब एक वर्ग में बहुत सारे WP फ़ंक्शन होते हैं तो यह दर्द हो सकता है।

सौभाग्य से, वहाँ अच्छे लोग हैं जो अच्छी चीजें लिखते हैं। सबसे बड़ी WP एजेंसियों में से एक 10up , उन लोगों के लिए एक बहुत ही बढ़िया पुस्तकालय रखता है, जो सही तरीके से प्लगइन्स का परीक्षण करना चाहते हैं। यह है WP_Mock

यह आपको WP फ़ंक्शंस को हुक करने की अनुमति देता है । मान लें कि आपने अपने परीक्षणों में लोड किया है (रेपो रीडमे देखें) वही परीक्षण जो मैंने ऊपर लिखा था वह बन जाता है:

class CustomPostTypes extends Custom_TestCase {

  function test_init() {
     $r = new RegisterCustomPostType;
     // tests that the action was added with given arguments
     \WP_Mock::expectActionAdded( 'init', array( $r, 'register_post_type' ) );
     $r->init();
  }

  function test_register_post_type() {
     // tests that the function was called with given arguments and run once
     \WP_Mock::wpFunction( 'register_post_type', array(
        'times' => 1,
        'args' => array( 'foo' ),
     ) );
     $r = new RegisterCustomPostType;
     $r->register_post_type();
  }

}

सरल, है ना? यह उत्तर एक ट्यूटोरियल नहीं है WP_Mock, इसलिए अधिक जानकारी के लिए रेपो रीडमे पढ़ें, लेकिन ऊपर दिया गया उदाहरण बहुत स्पष्ट होना चाहिए, मुझे लगता है।

इसके अलावा, आप किसी भी नकली add_actionया register_post_typeखुद को लिखने या किसी भी वैश्विक चर बनाए रखने की जरूरत नहीं है।

और WP कक्षाएं?

WP में कुछ कक्षाएं भी होती हैं, और यदि आप परीक्षण चलाते समय वर्डप्रेस लोड नहीं करते हैं, तो आपको उन्हें मॉक करने की आवश्यकता है।

मॉकिंग फ़ंक्शन की तुलना में यह बहुत आसान है, PHPUnit में ऑब्जेक्ट्स को मॉक करने के लिए एक एम्बेडेड सिस्टम है, लेकिन यहां मैं आपको Mockery का सुझाव देना चाहता हूं । यह बहुत शक्तिशाली पुस्तकालय है और उपयोग करने में बहुत आसान है। इसके अलावा, यह एक निर्भरता हैWP_Mock , इसलिए यदि आपके पास यह है तो आपके पास मॉकरी भी है।

लेकिन इससे क्या WP_UnitTestCase?

वर्डप्रेस कोर का परीक्षण करने के लिए वर्डप्रेस टेस्ट सूट बनाया गया था , और यदि आप कोर में योगदान करना चाहते हैं तो यह महत्वपूर्ण है, लेकिन प्लगइन्स के लिए इसका उपयोग करने से आप अलगाव में परीक्षण नहीं करते हैं।

WP की दुनिया में अपनी आँखें लगाएं: वहाँ बहुत सारे आधुनिक PHP फ्रेमवर्क और CMS हैं, उनमें से कोई भी फ्रेमवर्क कोड का उपयोग करके प्लगइन / मॉड्यूल / एक्सटेंशन (या जो भी उन्हें कहा जाता है) का परीक्षण करने का सुझाव देता है।

यदि आप कारखानों को याद करते हैं, तो सूट की एक उपयोगी विशेषता, आपको यह जानना होगा कि भयानक चीजें हैं हैं।

गोचर और अधोगति

एक ऐसा मामला है जब मेरे द्वारा सुझाए गए वर्कफ़्लो में कमी है: कस्टम डेटाबेस परीक्षण

वास्तव में, यदि आप वहाँ (निम्नतम स्तर पर लिखने के लिए मानक वर्डप्रेस टेबल और कार्यों का उपयोग $wpdbविधि) आप की जरूरत कभी नहीं वास्तव में लिखने डेटा या परीक्षण करता है, तो डेटा है वास्तव में डेटाबेस में, बस यह सुनिश्चित करें कि उचित तरीके उचित तर्क के साथ कहा जाता है हो सकता है।

हालाँकि, आप कस्टम टेबल और फ़ंक्शंस के साथ प्लगइन्स लिख सकते हैं जो वहां लिखने के लिए क्वेरीज़ का निर्माण करते हैं, और परीक्षण करते हैं कि क्या वे क्वेरीज़ आपकी जिम्मेदारी है।

उन मामलों में वर्डप्रेस टेस्ट सूट आपकी बहुत मदद कर सकता है, और फ़ंक्शंस को चलाने के लिए कुछ मामलों में लोडिंग वर्डप्रेस की आवश्यकता हो सकती है dbDelta

(परीक्षणों के लिए एक अलग डीबी का उपयोग करने के लिए कहने की आवश्यकता नहीं है, है न?)

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

केवल उन कक्षाओं को लिखना सुनिश्चित करें जो संभव के रूप में कई डेटाबेस संचालन को अमूर्त करते हैं, इस तरह से कि अन्य सभी प्लगइन वर्ग उनका उपयोग करते हैं, ताकि मोक्स का उपयोग करके आप डेटाबेस से निपटने के बिना कक्षाओं के बहुमत का सही परीक्षण कर सकें।

तीसरी बार, अलगाव में आसानी से लिखने योग्य कोड का अर्थ है बेहतर कोड लिखना।


5
पवित्र बकवास, बहुत सारी उपयोगी जानकारी! धन्यवाद! किसी तरह मैं यूनिट परीक्षण के पूरे बिंदु को याद करने में कामयाब रहा (अब तक, मैं केवल कोड डोजो के अंदर PHP परीक्षण का अभ्यास कर रहा था)। मुझे आज पहले wp_mock के बारे में भी पता चला, लेकिन किसी कारण से मैं इसे अनदेखा कर देता हूं। मुझे इस बात का अफ़सोस है कि कोई भी परीक्षा, चाहे वह कितनी भी छोटी क्यों न हो, उसे चलाने में कम से कम दो सेकंड का समय लगता था (पहले WP env लोड करें, परीक्षण दूसरा निष्पादित करें)। मेरी आँखें खोलने के लिए फिर से धन्यवाद!
आयनुत स्टाकिसू

4
धन्यवाद @IonutStaicu मैं भूल गया उल्लेख है कि लोड नहीं वर्डप्रेस अपने परीक्षण करता है एक बहुत तेजी से
gmazzap

6
यह भी इंगित करने के लायक है कि WP कोर इकाई परीक्षण रूपरेखा एकीकरण परीक्षण चलाने के लिए एक अद्भुत उपकरण है, जो यह सुनिश्चित करने के लिए स्वचालित परीक्षण होगा कि यह WP के साथ अच्छी तरह से एकीकृत है (जैसे कि कोई आकस्मिक कार्य नाम टकराव, आदि नहीं हैं)।
जॉन पी बलोच

1
@JohnPBloch +1 अच्छे अंक के लिए। भले ही WordPress में किसी भी फ़ंक्शन नाम के टकराने से बचने के लिए एक नेमस्पेस का उपयोग करना पर्याप्त है, जहां सब कुछ वैश्विक है :) लेकिन, निश्चित रूप से, एकीकरण / कार्यात्मक परीक्षण एक चीज है। मैं इस समय बेहट + मिंक के साथ खेल रहा हूं लेकिन मैं अभी भी इसके साथ अभ्यास कर रहा हूं।
gmazzap

1
वर्डप्रेस के यूनिटेस्ट वन में "हेलिकॉप्टर राइड" के लिए धन्यवाद - मैं अभी भी उस महाकाव्य चित्र पर हंस रहा हूं ;-)
बिरगायर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.