แพ็คเกจนี้ช่วยจำลองฟังก์ชัน php ภายในให้ง่ายที่สุด ใช้แพ็คเกจนี้เมื่อคุณต้องการจำลองฟังก์ชันเช่น: time()
, str_contains()
, rand
ฯลฯ
การติดตั้ง
การใช้งาน
จำลองรันไทม์
การเยาะเย้ยที่กำหนดไว้ล่วงหน้า
ผสมผสานสองวิธีก่อนหน้านี้
PHPหน่วยที่ 9
PHPUnit 10 และสูงกว่า
ลงทะเบียนส่วนขยาย PHPUnit
ลงทะเบียนเยาะเย้ย
สถานะ
ติดตามการโทร
ฟังก์ชันเนมสเปซสากล
การใช้งานฟังก์ชันภายใน
ฟังก์ชั่นภายใน
ข้อจำกัด
ผู้ให้บริการข้อมูล
ผู้แต่งต้องการ xepozz/internal-mocker --dev
แนวคิดหลักนั้นค่อนข้างง่าย: ลงทะเบียน Listener สำหรับ PHPUnit และเรียกส่วนขยาย Mocker ก่อน
สร้างไฟล์ใหม่ tests/MockerExtension.php
วางรหัสต่อไปนี้ลงในไฟล์ที่สร้างขึ้น:
<?phpdeclare(strict_types=1);namespace AppTests;ใช้ PHPUnitRunnerBeforeTestHook;ใช้ PHPUnitRunnerBeforeFirstTestHook;ใช้ XepozzInternalMockerMocker;ใช้ XepozzInternalMockerMockerState;MockerExtension คลาสสุดท้ายใช้ BeforeTestHook, BeforeFirstTestHook {ฟังก์ชันสาธารณะดำเนินการBeforeFirstTest(): เป็นโมฆะ{$mocks = [];$mocker = new Mocker();$mocker->load($mocks); MockerState::saveState(); }ฟังก์ชันสาธารณะดำเนินการBeforeTest(สตริง $test): เป็นโมฆะ{ MockerState::resetState(); - -
ลงทะเบียน hook เป็นส่วนขยายใน phpunit.xml.dist
<ส่วนขยาย> <คลาสส่วนขยาย = "AppTestsMockerExtension"/> </ส่วนขยาย>
สร้างไฟล์ใหม่ tests/MockerExtension.php
วางรหัสต่อไปนี้ลงในไฟล์ที่สร้างขึ้น:
<?phpdeclare(strict_types=1);namespace AppTests;ใช้ PHPUnitEventTestPreparationStarted;ใช้ PHPUnitEventTestPreparationStartedSubscriber;ใช้ PHPUnitEventTestSuiteStarted;ใช้ PHPUnitEventTestSuiteStartedSubscriber;ใช้ PHPUnitRunnerExtensionExtension;ใช้ PHPUnitRunnerExtensionFacade;ใช้ PHPUnitRunnerExtensionParameterCollection; ใช้ PHPUnitTextUIConfigurationConfiguration; ใช้ XepozzInternalMockerMocker; ใช้ XepozzInternalMockerMockerState; MockerExtension คลาสสุดท้ายใช้ส่วนขยาย {บูตฟังก์ชันสาธารณะ (การกำหนดค่า $configuration, Facade $facade, parameterCollection $parameters): โมฆะ{$facade->registerSubscribers(คลาสใหม่ () ใช้ StartedSubscriber {ฟังก์ชันสาธารณะแจ้งเตือน (เริ่มต้น $event): โมฆะ{ MockerExtension::โหลด(); - } คลาสใหม่ใช้ PreparationStartedSubscriber {ฟังก์ชันสาธารณะแจ้งเตือน (PreparationStarted $event): เป็นโมฆะ{ MockerState::resetState(); - - - } โหลดฟังก์ชันคงที่สาธารณะ (): เป็นโมฆะ {$mocks = [];$mocker = new Mocker();$mocker->load($mocks); MockerState::saveState(); - -
ลงทะเบียน hook เป็นส่วนขยายใน phpunit.xml.dist
<ส่วนขยาย> <คลาสบูตสแตรป = "AppTestsMockerExtension"/> </ส่วนขยาย>
ที่นี่คุณได้ลงทะเบียนส่วนขยายที่จะถูกเรียกทุกครั้งเมื่อคุณเรียกใช้ ./vendor/bin/phpunit
phpunit
ตามค่าเริ่มต้น ฟังก์ชั่นทั้งหมดจะถูกสร้างขึ้นและบันทึกลงในไฟล์ /vendor/bin/xepozz/internal-mocker/data/mocks.php
แทนที่อาร์กิวเมนต์แรกของตัวสร้าง Mocker
เพื่อเปลี่ยนเส้นทาง:
$mocker = ตัวเยาะเย้ยใหม่('/path/to/your/mocks.php');
แพ็คเกจรองรับฟังก์ชันจำลองสองสามวิธี:
จำลองรันไทม์
เยาะเย้ยที่กำหนดไว้ล่วงหน้า
ผสมผสานสองวิธีก่อนหน้านี้
หากคุณต้องการให้กรณีทดสอบของคุณใช้กับฟังก์ชันจำลองคุณควรลงทะเบียนก่อน
กลับไปที่ MockerExtension::executeBeforeFirstTest
ที่สร้างขึ้น และแก้ไขตัวแปร $mocks
$เยาะเย้ย = [ ['namespace' => 'AppService','name' => 'เวลา', - -
การเยาะเย้ยนี้จะพร็อกซีทุกครั้งที่เรียก time()
ภายใต้เนมสเปซ AppService
ผ่าน wrapper ที่สร้างขึ้น
เมื่อคุณต้องการจำลองผลลัพธ์ในการทดสอบ คุณควรเขียนโค้ดต่อไปนี้ลงในกรณีทดสอบที่จำเป็น:
MockerState::addCondition( 'AppService', // namespace 'เวลา' // ชื่อฟังก์ชัน [], // อาร์กิวเมนต์ 100 // ผลลัพธ์);
คุณอาจใช้การโทรกลับเพื่อกำหนดผลลัพธ์ของฟังก์ชัน:
MockerState::addCondition( '', // namespace 'headers_sent', // ชื่อฟังก์ชัน [null, null], // อาร์กิวเมนต์ทั้งสองเป็นข้อมูลอ้างอิงและยังไม่ได้เตรียมใช้งานในการเรียกใช้ฟังก์ชัน fn (&$file, &$line) => $file = $line = 123, // ผลการโทรกลับ);
ดังนั้นกรณีทดสอบของคุณจะมีลักษณะดังนี้:
<?phpnamespace AppTests;ใช้ AppService;ใช้ PHPUnitFrameworkTestCase;class ServiceTest ขยาย TestCase {ฟังก์ชันสาธารณะ testRun2(): เป็นโมฆะ{$service = บริการใหม่(); MockerState::addCondition('AppService','เวลา', [],100);$this->assertEquals(100, $service->doSomething()); - -
ดูตัวอย่างเต็มใน XepozzInternalMockerTestsIntegrationDateTimeTest::testRun2
การเยาะเย้ยที่กำหนดไว้ล่วงหน้าทำให้คุณสามารถเยาะเย้ยพฤติกรรมได้ทั่วโลก
หมายความว่าคุณไม่จำเป็นต้องเขียน MockerState::addCondition(...)
ลงในแต่ละกรณีทดสอบหากคุณต้องการจำลองมันสำหรับทั้งโครงการ
โปรดทราบว่าฟังก์ชันเดียวกันจากเนมสเปซที่ต่างกันจะไม่เหมือนกันสำหรับ
Mocker
กลับไปที่ MockerExtension::executeBeforeFirstTest
ที่สร้างขึ้น และแก้ไขตัวแปร $mocks
$เยาะเย้ย = [ ['namespace' => 'AppService','name' => 'time','result' => 150,'arguments' => [], - -
หลังจากตัวแปรนี้ แต่ละ AppServicetime()
จะส่งกลับ 150
คุณสามารถเพิ่มการเยาะเย้ยได้มากมาย Mocker
เปรียบเทียบค่า arguments
กับอาร์กิวเมนต์ของการเรียกใช้ฟังก์ชันและส่งกลับผลลัพธ์ที่ต้องการ
Mix หมายความว่าคุณสามารถใช้ การจำลองที่กำหนดไว้ล่วงหน้า ในตอนแรกและ การจำลองรันไทม์ หลังจากนั้นได้
หากคุณใช้ Runtime mock
คุณอาจประสบปัญหาว่าหลังจากฟังก์ชัน mocking แล้ว คุณยังคงถูกเยาะเย้ยในกรณีทดสอบอื่น
MockerState::saveState()
และ MockerState::resetState()
แก้ปัญหานี้ได้
วิธีการเหล่านี้จะบันทึกสถานะ "ปัจจุบัน" และยกเลิกการโหลดการจำลอง Runtime mock
แต่ละรายการที่ใช้
การใช้ MockerState::saveState()
หลังจาก Mocker->load($mocks)
จะบันทึกเฉพาะการจำลอง ที่กำหนดไว้ล่วงหน้า เท่านั้น
คุณสามารถติดตามการเรียกใช้ฟังก์ชันที่จำลองได้โดยใช้เมธอด MockerState::getTraces()
$traces = MockerState::getTraces('AppService', 'time');
$traces
จะมีอาร์เรย์ของอาร์เรย์ที่มีโครงสร้างดังต่อไปนี้:
- ['arguments' => [], // อาร์กิวเมนต์ของ function'trace' => [], // ผลลัพธ์ของ debug_backtrace function'result' => 1708764835, // ผลลัพธ์ของฟังก์ชัน],// ... ]
ฟังก์ชั่นภายในทั้งหมดถูกจำกัดให้เข้ากันได้กับฟังก์ชั่นดั้งเดิม มันทำให้ฟังก์ชั่นใช้อาร์กิวเมนต์ที่อ้างอิง ( &$file
) เช่นเดียวกับต้นฉบับ
ตั้งอยู่ในไฟล์ src/stubs.php
หากคุณต้องการเพิ่มลายเซ็นฟังก์ชันใหม่ ให้แทนที่อาร์กิวเมนต์ที่สองของตัวสร้าง Mocker
:
$mocker = ตัวเยาะเย้ยใหม่ (stubPath: '/path/to/your/stubs.php');
วิธีที่คุณสามารถจำลองฟังก์ชั่นระดับโลกคือการปิดการใช้งานใน php.ini
: https://www.php.net/manual/en/ini.core.php#ini.disable-functions
วิธีที่ดีที่สุดคือการปิดการใช้งานสำหรับการทดสอบเท่านั้นโดยการรันคำสั่งพร้อมแฟล็กเพิ่มเติม:
php -ddisable_functions=${functions} ./vendor/bin/phpunit
หากคุณใช้ PHPStorm คุณสามารถตั้งค่าคำสั่งได้ในส่วน
Run/Debug Configurations
เพิ่มแฟล็ก-ddisable_functions=${functions}
ลงในฟิลด์Interpreter options
คุณสามารถเก็บคำสั่งไว้ในไฟล์
composer.json
ใต้ส่วนscripts
{ "scripts": {"test": "php -ddisable_functions=time,serialize,header,date ./vendor/bin/phpunit" - -
แทนที่
${functions}
ด้วยรายการฟังก์ชันที่คุณต้องการจำลอง โดยคั่นด้วยเครื่องหมายจุลภาค เช่นtime,rand
ตอนนี้คุณสามารถจำลองฟังก์ชันโกลบอลได้เช่นกัน
เมื่อคุณปิดการใช้งานฟังก์ชั่นใน php.ini
คุณจะไม่สามารถเรียกมันได้อีกต่อไป นั่นหมายความว่าคุณต้องปฏิบัติด้วยตัวเอง
แน่นอนว่าฟังก์ชั่นเกือบทั้งหมดถูกนำมาใช้ใน PHP มีลักษณะเหมือนกับฟังก์ชั่น Bash
วิธีที่สั้นที่สุดในการใช้งานฟังก์ชันคือการใช้ไวยากรณ์ `bash command`
:
$mocks[] = [ 'namespace' => '', 'name' => 'time', 'function' => fn () => `date +%s`, -
โปรดทราบว่าการละทิ้งฟังก์ชันส่วนกลางโดยไม่มีการใช้งานจะทำให้เกิดการเรียกใช้ฟังก์ชันดังกล่าว ซึ่งจะนำไปสู่ข้อผิดพลาดร้ายแรง
บางครั้งคุณอาจเผชิญกับสถานการณ์ที่ไม่พึงประสงค์เมื่อฟังก์ชันที่เยาะเย้ยไม่ได้ถูกเยาะเย้ยโดยไม่ถูกบังคับให้ใช้ namespace
function
. อาจหมายความว่าคุณกำลังพยายามสร้างไฟล์ล่าม PHP ใน @dataProvider
โปรดใช้ความระมัดระวังและเป็นวิธีแก้ปัญหา ฉันอาจแนะนำให้คุณเรียกผู้เยาะเย้ยในตัวสร้างการทดสอบ ดังนั้นก่อนอื่นให้ย้ายโค้ดทั้งหมดจากวิธีส่วนขยายของคุณ executeBeforeFirstTest
ไปยังวิธีคงที่ใหม่และเรียกมันทั้งในวิธี executeBeforeFirstTest
และ __construct
MyTest คลาสสุดท้ายขยาย PHPUnitFrameworkTestCase {ฟังก์ชันสาธารณะ __construct(?string $name = null, array $data = [], $dataName = '') {AppTestsMockerExtension::load();parent::__construct($name, $data, $dataName); -
MockerExtension คลาสสุดท้ายใช้ BeforeTestHook, BeforeFirstTestHook {ฟังก์ชันสาธารณะดำเนินการBeforeFirstTest(): เป็นโมฆะ{self::load(); } โหลดฟังก์ชันคงที่สาธารณะ (): เป็นโมฆะ {$mocks = [];$mocker = new Mocker();$mocker->load($mocks); MockerState::saveState(); }ฟังก์ชันสาธารณะดำเนินการBeforeTest(สตริง $test): เป็นโมฆะ{ MockerState::resetState(); - -
ทั้งหมดนี้เป็นเพราะ PHPUnit 9.5 และระบบจัดการเหตุการณ์ที่ต่ำกว่า ฟังก์ชันการทำงานของผู้ให้บริการข้อมูลเริ่มทำงานก่อนเหตุการณ์ใดๆ ดังนั้นจึงเป็นไปไม่ได้ที่จะจำลองฟังก์ชันเมื่อเริ่มต้นรันไทม์