अलगाव में परीक्षण
एक प्लगइन विकसित करते समय, यह परीक्षण करने का सबसे अच्छा तरीका वर्डप्रेस पर्यावरण को लोड किए बिना है।
यदि आप ऐसे कोड लिखते हैं, जो वर्डप्रेस के बिना आसानी से जांचे जा सकते हैं, तो आपका कोड बेहतर हो जाता है ।
प्रत्येक घटक जो इकाई परीक्षण किया जाता है, उसे अलगाव में परीक्षण किया जाना चाहिए : जब आप एक वर्ग का परीक्षण करते हैं, तो आपको केवल उस विशिष्ट वर्ग का परीक्षण करना होगा, यह मानते हुए कि अन्य सभी कोड पूरी तरह से काम कर रहे हैं।
यही कारण है कि यूनिट परीक्षणों को "यूनिट" कहा जाता है।
एक अतिरिक्त लाभ के रूप में, लोडिंग कोर के बिना, आपका परीक्षण बहुत तेज़ी से चलेगा।
कंस्ट्रक्टर में हुक से बचें
एक टिप जो मैं आपको दे सकता हूं, वह है कंस्ट्रक्टरों में हुक लगाने से बचना। यह उन चीजों में से एक है जो आपके कोड को अलगाव में परीक्षण योग्य बना देगा।
आइए देखें ओपी में परीक्षण कोड:
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 आपको "सूट" में अपने परीक्षणों को व्यवस्थित करने की अनुमति देता है जो अलग-अलग चलाए जा सकते हैं, इसलिए आप कस्टम डेटाबेस परीक्षणों के लिए एक सूट लिख सकते हैं जहां आप वर्डप्रेस वातावरण (या इसका हिस्सा) को लोड करते हैं, जिससे आपके सभी परीक्षण वर्डप्रेस-फ्री हो जाते हैं ।
केवल उन कक्षाओं को लिखना सुनिश्चित करें जो संभव के रूप में कई डेटाबेस संचालन को अमूर्त करते हैं, इस तरह से कि अन्य सभी प्लगइन वर्ग उनका उपयोग करते हैं, ताकि मोक्स का उपयोग करके आप डेटाबेस से निपटने के बिना कक्षाओं के बहुमत का सही परीक्षण कर सकें।
तीसरी बार, अलगाव में आसानी से लिखने योग्य कोड का अर्थ है बेहतर कोड लिखना।
phpunit
, तो क्या आप असफल या उत्तीर्ण परीक्षण देख सकते हैं? क्या आपने स्थापित कियाbin/install-wp-tests.sh
?