Magento 2 में PHPUnit 4.1 के साथ PHP7 कोड के परीक्षण के लिए उचित तरीका क्या है?


23

जब मैं अपने मॉड्यूल लिख रहा होता हूं, तो मैं उन्हें एप्लिकेशन के सबसे महत्वपूर्ण भागों के लिए यूनिट-परीक्षणों के साथ आपूर्ति करने की कोशिश कर रहा हूं। हालाँकि, इस समय (मैगेंटो 2.1.3) यूनिट परीक्षण लिखने के कई तरीके हैं:

परीक्षण के विभिन्न तरीके

  • इसके साथ इंटीग्रेट करें bin/magento dev:tests:run unitऔर इसे Magento के साथ तयशुदा phpunit सेटिंग्स के शीर्ष पर चलाएं।
  • उन्हें अलग से लिखें, उन्हें चलाएं vendor/bin/phpunit app/code/Vendor/Module/Test/Unitऔर वह सब कुछ मॉक करें जो मैगेंटो है।
  • उन्हें अलग से लिखें, सब कुछ मॉक करें और PHPUnit के सिस्टम-ग्लोबल संस्करण का उपयोग करें।
  • उन्हें अलग से लिखें, उनके साथ चलाएं vendor/bin/phpunit, लेकिन फिर भी उपयोग करें \Magento\Framework\TestFramework\Unit\Helper\ObjectManager

Magento 2 और PHPUnit

इसके अलावा, Magento 2 PHPUnit 4.1.0 के साथ आता है, जो PHP7- संगत नहीं है। टाइप-हिंटिंग नेटिव्स (जैसे stringऔर `इंट) और आपके हस्ताक्षरों में रिटर्न प्रकार घोषित करने से त्रुटियां होंगी। उदाहरण के लिए, इस तरह एक विधि हस्ताक्षर के साथ एक इंटरफ़ेस / वर्ग:

public function foo(string $bar) : bool;

... PHPUnit 4.1.0 द्वारा मजाक नहीं किया जा सकेगा। :-(

मेरी वर्तमान स्थिति

यह इस कारण से है कि मैं अब अपने यूनिट परीक्षणों को तीसरे तरीके से लिख रहा हूं (सिस्टम-ग्लोबल PHPUnit संस्करण को कॉल करके)।

मेरे सेटअप में, मेरे पास PHPUnit 5.6 विश्व स्तर पर स्थापित है, इसलिए मैं उचित PHP7-कोड लिख सकता हूं, लेकिन मुझे कुछ ट्विक्स करने होंगे। उदाहरण के लिए:

phpunit.xml इस तरह दिखना है तो मैं संगीतकार ऑटोलैडर का उपयोग कर सकता हूं:

<?xml version="1.0"?>
<phpunit bootstrap="../../../../../../vendor/autoload.php"
         colors="true">
    <testsuites>
        <testsuite name="Testsuite">
            <directory>.</directory>
        </testsuite>
    </testsuites>
</phpunit>

... और मेरे सभी setUp()मैथोड्स में, मेरे पास निम्नलिखित जांच है ताकि मैं अपने परीक्षणों को आगे-संगतता के साथ लिख सकूं:

// Only allow PHPUnit 5.x:
if (version_compare(\PHPUnit_Runner_Version::id(), '5', '<')) {
    $this->markTestSkipped();
}

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

मेरा प्रश्न

तो यहाँ मेरा सवाल है: क्या यह इकाई परीक्षणों को लिखने का एक 'स्वस्थ' तरीका है? क्योंकि यह मुझे सही नहीं लगता कि मैगेंटो परीक्षण के साथ सहायता करने के लिए उपकरणों की एक पूरी गुच्छा के साथ बंडल में आता है और मैं PHP7 के साथ होने के कारण उनका उपयोग नहीं कर सकता। मुझे पता है कि GitHub पर टिकट हैं जो इस मुद्दे को संबोधित करते हैं, लेकिन मुझे आश्चर्य है कि समुदाय वर्तमान में कैसे लिख रहा है यह परीक्षण है।

क्या Magento 2 में यूनिट टेस्ट लिखने का एक तरीका है, इसलिए मुझे अपने कोड को 'डाउनग्रेड' करने की आवश्यकता नहीं है और फिर भी ऑब्जेक्ट मैनेजर को सब कुछ मॉक करने के लिए मैगेंटोस के अंतर्निहित हेल्पर्स का उपयोग कर सकते हैं? या आपके यूनिट परीक्षणों में भी वस्तु प्रबंधक का उपयोग करना बुरा है?

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


1
क्या शानदार सवाल है।
कैमडिक्सन

जवाबों:


17

बंडल किए गए PHPUnit संस्करण का उपयोग करना, भले ही यह प्राचीन हो, शायद जाने का सबसे अच्छा तरीका है क्योंकि यह सभी मॉड्यूल के लिए परीक्षणों को सीआई के दौरान एक साथ चलाने की अनुमति देगा।

मुझे लगता है कि ऐसे तरीके से परीक्षण लिखना जो बंडल किए गए परीक्षण ढांचे के साथ असंगत है, परीक्षणों के मूल्य को बहुत कम कर देता है।
बेशक आप PHPUnit के एक अलग संस्करण के साथ अपने परीक्षण चलाने के लिए CI की स्थापना कर सकते हैं, लेकिन यह निर्माण प्रणाली में बहुत अधिक जटिलता जोड़ता है।

उस ने कहा, मैं आपसे सहमत हूं कि यह PHP 5.6 का समर्थन करने लायक नहीं है। मैं PHP7 स्केलर टाइप हिन्टिंग का उपयोग करता हूं और जितना संभव हो उतना हाइनिंग टाइप करता हूं (साथ ही, मुझे मार्केट प्लेस की परवाह नहीं है)।

PHPUnit 4.1 मॉकिंग लाइब्रेरी की सीमाओं के इर्द-गिर्द काम करने के लिए, पिछले कम से कम दो बार आगे के वर्कअराउंड हैं जो मैंने पिछले उपयोग किए हैं:

  1. उदाहरण के लिए, अपने परीक्षण डबल्स के निर्माण के लिए अनाम या नियमित कक्षाओं का उपयोग करें

    $fooIsFalseStub = new class extends Foo implements BarInterface() {
        public function __construct(){};
        public function isSomethingTrue(string $something): bool
        {
            return false;
        }
    };
    
  2. बंडल किए गए PHPUnit का उपयोग करें लेकिन एक तीसरे पक्ष की मॉकिंग लाइब्रेरी जिसे संगीतकार के माध्यम से शामिल किया जा सकता है require-dev, उदाहरण के लिए https://github.com/padraic/mockery । मैंने कोशिश की सभी मॉकिंग लाइब्रेरी को बहुत आसानी से किसी भी टेस्टिंग फ्रेमवर्क के साथ इस्तेमाल किया जा सकता है, यहां तक ​​कि 4.1 की तरह PHPUnit का एक बहुत पुराना संस्करण।

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

व्यक्तिगत रूप से मैं अनाम कक्षाओं का उपयोग करना पसंद करता हूं क्योंकि यह बाहरी निर्भरता की संख्या में नहीं जोड़ता है, और यह भी कि उन्हें इस तरह से लिखना अधिक मजेदार है।

संपादित करें :
अपने सवालों के जवाब देने के लिए:

क्या Mockery PHPUnit 4.1.0 की समस्या को '' हल '' करता है जो ठीक से PHP7 प्रकार की हिंटिंग को संभालने में सक्षम नहीं है?

हां, नीचे दिया गया उदाहरण देखें।

और नकल करने पर अनाम वर्गों के क्या लाभ हैं?

टेस्ट डबल्स बनाने के लिए अनाम कक्षाओं का उपयोग करना "मॉकिंग" भी है, यह वास्तव में मॉकिंग लाइब्रेरी जैसे कि PHPUnits या Mockery या किसी अन्य का उपयोग करने से अलग नहीं है।
एक नकली केवल विशिष्ट प्रकार के परीक्षण दोहरे पर है , भले ही यह कैसे बनाया गया हो।
अनाम कक्षाओं या मॉकिंग लाइब्रेरी का उपयोग करने के बीच एक छोटा सा अंतर यह है कि अनाम कक्षाओं में बाहरी लाइब्रेरी निर्भरता नहीं होती है, क्योंकि यह केवल सादे PHP है। अन्यथा कोई लाभ या कमियां नहीं हैं। यह केवल वरीयता की बात है। मुझे यह पसंद है क्योंकि यह दिखाता है कि परीक्षण किसी भी परीक्षण ढांचे या मॉकिंग लाइब्रेरी के बारे में नहीं है, परीक्षण सिर्फ लेखन कोड है जो परीक्षण के तहत प्रणाली को निष्पादित करता है और स्वचालित रूप से यह काम करता है।

और 5.3.5 में मुख्य कंपोजर.जॉन फ़ाइल में PHPUnit संस्करण को अपडेट करने के बारे में कैसे जानें (PHP7 का समर्थन करने वाला नवीनतम संस्करण सार्वजनिक मॉकिंग-मेथड्स (मैगेंटो 2 के स्वयं के परीक्षणों के लिए आवश्यक है)?

यह समस्याग्रस्त हो सकता है क्योंकि अन्य मॉड्यूल में परीक्षण और कोर केवल PHPUnit 4.1 के साथ परीक्षण किए जाते हैं, और जैसे कि आप CI में झूठी विफलताओं का सामना कर सकते हैं। मुझे लगता है कि उस कारण से PHPUnit के बंडल संस्करण के साथ रहना सबसे अच्छा है। @maksek ने कहा कि वे PHPUnit को अपडेट करेंगे, लेकिन इसके लिए कोई ईटीए नहीं है।


Mockery लाइब्रेरी का उपयोग करके PHPUnit 4.1 के साथ PHP7 चलाने के लिए आवश्यक एक वर्ग के टेस्ट डबल के साथ टेस्ट का उदाहरण:

<?php

declare(strict_types = 1);

namespace Example\Php7\Test\Unit;

// Foo is a class that will not work with the mocking library bundled with PHPUnit 4.1 
// The test below creates a mock of this class using mockery and uses it in a test run by PHPUnit 4.1
class Foo
{
    public function isSomethingTrue(string $baz): bool
    {
        return 'something' === $baz; 
    }
}

// This is another class that uses PHP7 scalar argument types and a return type.
// It is the system under test in the example test below.
class Bar
{
    private $foo;

    public function __construct(Foo $foo)
    {
        $this->foo = $foo;
    }

    public function useFooWith(string $s): bool
    {
        return $this->foo->isSomethingTrue($s);
    }
}

// This is an example test that runs with PHPUnit 4.1 and uses mockery to create a test double
// of a class that is only compatible with PHP7 and younger.
class MockWithReturnTypeTest extends \PHPUnit_Framework_TestCase
{
    protected function tearDown()
    {
        \Mockery::close();
    }

    public function testPHPUnitVersion()
    {
        // FYI to show this test runs with PHPUnit 4.1
        $this->assertSame('4.1.0', \PHPUnit_Runner_Version::id());
    }

    public function testPhpVersion()
    {
        // FYI this test runs with PHP7
        $this->assertSame('7.0.15', \PHP_VERSION);
    }

    // Some nonsensical example test using a mock that has methods with
    // scalar argument types and PHP7 return types.
    public function testBarUsesFoo()
    {
        $stubFoo = \Mockery::mock(Foo::class);
        $stubFoo->shouldReceive('isSomethingTrue')->with('faz')->andReturn(false);
        $this->assertFalse((new Bar($stubFoo))->useFooWith('faz'));
    }
}

क्या Mockery PHPUnit 4.1.0 की समस्या को '' हल '' करता है जो ठीक से PHP7 प्रकार की हिंटिंग को संभालने में सक्षम नहीं है? और नकल करने पर अनाम वर्गों के क्या लाभ हैं? और composer.json5.3.5 के लिए मुख्य फ़ाइल में PHPUnit संस्करण को अपडेट करने के बारे में कैसे पता चलता है (PHP7 का समर्थन करने वाला नवीनतम संस्करण सार्वजनिक मॉकिंग-मेथड है (मैगेंटो 2 के स्वयं के परीक्षणों द्वारा आवश्यक है))? अब और भी कई सवाल ...
Giel Berkers

आपके प्रश्न के उत्तर में मेरा उत्तर अपडेट किया गया @GielBerkers
Vinai

आपके शानदार जवाब के लिए धन्यवाद। यह अब पूरी तरह से स्पष्ट है! मुझे लगता है कि मैं जाऊंगा और फिर मॉकरी को आजमाऊंगा। अनाम कक्षाएं ऐसा लगता है कि मुझे बहुत कुछ फिर से आविष्कार करना होगा जो मॉकरी पहले से ही प्रदान करता है। मैं पहले PHPUnit की मूल बातें सीखना चाहता था और वहां से आगे बढ़ना चाहता था। मुझे लगता है कि अब समय आ गया है।
गियल बर्क

महान! एक महान पुस्तकालय, मॉकरी की खोज का आनंद लें। जब आप इस पर होते हैं, तो शायद हैमरेस्ट, भी, एक परख पुस्तकालय देखें - यह स्वचालित रूप से मॉकरी के साथ स्थापित किया जाएगा।
विन्ह

3

अभी Magento 2 अगले PHP संस्करणों का समर्थन करता है:

"php": "~5.6.5|7.0.2|7.0.4|~7.0.6"

इसका मतलब है कि Magento टीम द्वारा लिखा गया सभी कोड हर समर्थित संस्करण पर काम करता है।

इसलिए Magento Team केवल PHP 7 सुविधाओं का उपयोग नहीं करता है। PHP 5.6 फीचर को PHPUnit 4.1.0 के साथ कवर किया जा सकता है।

अपना खुद का कोड लिखना आप अपनी इच्छानुसार सभी कर सकते हैं और किसी भी तरह से परीक्षण लिख सकते हैं। लेकिन मेरा मानना ​​है कि आवश्यकताओं के उल्लंघन के कारण आप Magento Marketplace पर अपना एक्सटेंशन प्रकाशित नहीं कर पाएंगे।


दरअसल, PHPUnit 5.7 PHP 5.6, PHP 7.0 और PHP 7.1 पर समर्थित है। PHPUnit 4.8 PHP 5.3 - 5.6 पर समर्थित था। भले ही Magento 2 PHP 5.6 का समर्थन करता है, यह अभी भी PHPUnit 5.7 में अपग्रेड कर सकता है।
विनय
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.