Magento 2에서 PHPUnit 4.1로 PHP7 코드를 유닛 테스트하는 올바른 방법은 무엇입니까?


23

모듈을 작성할 때 응용 프로그램의 가장 중요한 부분에 대한 단위 테스트를 제공하려고합니다. 그러나 현재 단위 테스트를 작성하는 방법에는 몇 가지 방법이 있습니다 (Magento 2.1.3).

다른 테스트 방법

  • bin/magento dev:tests:run unitMagento와 함께 번들로 제공되는 기본 phpunit 설정과 통합하여 실행하십시오.
  • 별도로 작성하고 vendor/bin/phpunit app/code/Vendor/Module/Test/UnitMagento 인 모든 것을 사용 하여 조롱하십시오.
  • 별도로 작성하고 모든 것을 조롱하고 시스템 전역 버전의 PHPUnit을 사용하십시오.
  • 별도로 작성하고로 실행 vendor/bin/phpunit하지만 여전히 사용하십시오 \Magento\Framework\TestFramework\Unit\Helper\ObjectManager.

마 젠토 2와 PHPUnit

게다가 Magento 2는 PHP7과 호환되지 않는 PHPUnit 4.1.0과 함께 제공됩니다. 타입 힌트 네이티브 ( stringin 및`int)와 서명에 리턴 타입을 선언하면 에러가 발생합니다. 예를 들어, 다음과 같은 메소드 서명이있는 인터페이스 / 클래스 :

public function foo(string $bar) : bool;

... PHPUnit 4.1.0에서는 조롱 할 수 없습니다. :-(

내 현재 상황

이 때문에 필자는 현재 시스템 전역 PHPUnit 버전을 호출하여 세 번째 방식으로 단위 테스트를 작성하고 있습니다.

내 설정에서 PHPUnit 5.6을 전역에 설치 했으므로 올바른 PHP7 코드 작성을 해결할 수 있지만 약간의 조정이 필요합니다. 예를 들면 다음과 같습니다.

phpunit.xml composer autoloader를 사용할 수 있도록 다음과 같이 보여야합니다.

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

이렇게하면 Magentos의 내장 PHPUnit에서 테스트를 실행할 때 오류가 발생하지 않습니다.

내 질문

여기 내 질문이 있습니다 : 이것이 단위 테스트를 작성하는 '건강한'방법입니까? Magento에는 테스트를 돕기 위해 많은 도구가 번들로 포함되어 있으며 PHP7을 사용하고 있기 때문에 사용할 수 없습니다. GitHub에는이 문제를 해결하는 티켓이 있지만 커뮤니티에서 현재 테스트를 작성하는 방법이 궁금합니다.

Magento 2에서 단위 테스트를 작성하는 방법이 있습니까? 그래서 코드를 '다운 그레이드'할 필요는 없지만 객체 관리자가 만지는 모든 것을 조롱하는 데 여전히 Magentos의 내장 도우미를 사용할 수 있습니까? 아니면 단위 테스트에서도 객체 관리자를 사용하는 것이 나쁜 습관입니까?

나만의 커스텀 모듈을 유닛 테스트하는 방법에 대한 많은 지침 / 예제가 빠져 있습니다.


1
정말 좋은 질문입니다.
camdixon

답변:


17

번들로 제공되는 PHPUnit 버전을 사용하는 것은 고대 버전이더라도 CI 동안 모든 모듈에 대한 테스트를 함께 실행할 수 있기 때문에 가장 좋은 방법입니다.

번들 테스트 프레임 워크와 호환되지 않는 방식으로 테스트를 작성하면 테스트의 가치가 크게 줄어 듭니다.
물론 다른 버전의 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 또는 다른 것과 같은 모의 라이브러리를 사용하는 것과 실제로 다르지 않습니다.
모의 는 작성 방법에 관계없이 특정 유형의 테스트 double 에 있습니다.
익명 클래스 또는 조롱 라이브러리를 사용하는 것의 작은 차이점은 익명 클래스는 단순한 PHP이기 때문에 외부 라이브러리 종속성이 없다는 것입니다. 그렇지 않으면 이점이나 단점이 없습니다. 그것은 단순히 선호의 문제입니다. 테스트가 테스트 프레임 워크 또는 모의 라이브러리에 관한 것이 아니라는 것을 보여주기 때문에 테스트가 진행됩니다. 테스트는 테스트중인 시스템을 실행하고 자동으로 작동하는지 확인하는 코드를 작성하는 것입니다.

그리고 메인 composer.json 파일의 PHPUnit 버전을 5.3.5 (공개 모의 방법을 가진 PHP7을 지원하는 최신 버전 (Magento 2의 자체 테스트에 필요)으로 업데이트하는 방법은 어떻습니까?

다른 모듈 및 코어의 테스트는 PHPUnit 4.1에서만 테스트되므로 CI에서 잘못된 오류가 발생할 수 있으므로 문제가 될 수 있습니다. 그런 이유로 번들로 제공되는 PHPUnit 버전을 사용하는 것이 가장 좋습니다. @maksek은 PHPUnit을 업데이트 할 것이라고 말했지만 그에 대한 ETA는 없습니다.


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.json파일 의 PHPUnit 버전 을 5.3.5로 업데이트하는 방법은 어떻습니까? 이제 더 많은 질문이 있습니다 ...
Giel Berkers

귀하의 질문에 따라 답변이 업데이트되었습니다 @GielBerkers
Vinai

큰 답변 주셔서 감사합니다. 지금은 분명하다! 나는 내가 가서 Mockery를 시험해 볼 것이라고 생각한다. 익명 클래스는 이미 Mockery가 제공하는 많은 것을 다시 발명 해야하는 것처럼 보입니다. 먼저 PHPUnit의 기본 사항을 배우고 거기서부터 시작하고 싶었습니다. 나는 지금 시간이 있다고 생각합니다.
Giel Berkers

큰! 훌륭한 도서관 인 Mockery를 둘러보세요. 당신이 그것을 가지고있는 동안, 어설 션 라이브러리 인 hamcrest도 확인하십시오-Mockery와 함께 자동으로 설치됩니다.
Vinai

3

현재 Magento 2는 다음 PHP 버전을 지원합니다 :

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

Magento Team이 작성한 모든 코드는 모든 지원되는 버전에서 작동합니다.

따라서 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로 업그레이드 할 수 있습니다.
Vinai
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.