макетна некласова функция в теста на phpunit

Имам необработен PHP код за цикъл for-each. Използвам php 7.2 и PHPUnit 8.

ето името на файла app.php и кодът е даден по-долу: Тук имам друго извикване CalculatorAPI(), което изисква извикване на API - имам нужда и от макет.

$list = file_get_contents('input.txt');
$inputData = explode("\n", trim($list));

function main ( $inputData ) {
   foreach ($inputData as $row) {
    if (empty($row)) break;

    //explode row
    $p = explode(",", $row);

    // retrieve bin, amount and currency
    $p2 = explode(':', $p[0]);
    $currency = trim($p2[1], '"}');

    // Class which needs a mock up because it requires API call
    $calApi = new CalculatorAPI(); 
    $result =$calApi->getFinalResult($currency);

    echo $result;
    print "\n";
   }
}

main( $inputData );

Имайте предвид, че: в input.txt имам {"currency":"EUR"}... за получаване на списък с валути.

Сега трябва да напиша някакъв код за PHPUnit test:: тук е тестовият файл

<?php

require_once __DIR__."/../app.php";

use PHPUnit\Framework\TestCase;

class AppTest extends TestCase
{

    public function testApp() : void
    {
        $calAPI = $this->createStub(CalculatorAPI::class);
        $calAPI->method('getFinalResult')
            ->willReturn(1);

        $result = main($this->data, $calAPI);

        $this->assertEquals(1, $result);
    }

}

когато стартирам това, той изпълнява файла. Как да напиша код за raw PHP? Освен това трябва да стартирам теста офлайн, въпреки че изисква извикване на API.


person Selim Reza    schedule 03.05.2020    source източник
comment
Може би, ако го тествате, сякаш е друга CLI програма (stackoverflow.com/questions/17700653/).   -  person Nigel Ren    schedule 03.05.2020
comment
@NigelRen .. Работи. Но това не е правилният начин,   -  person Selim Reza    schedule 08.05.2020
comment
@NigelRen Трябва да изпълня теста и офлайн. и изискваше извикване на API   -  person Selim Reza    schedule 08.05.2020


Отговори (1)


Трябва да обвиете своя foreach код във функция, да речем myForeach, за да предотвратите изпълнението му в require_once __DIR__."/../app.php"; време.

След това от вашия тест трябва да изпълните вашата myForeach функция. Във вашия тест трябва да уловите изхода на вашата myForeach функция. След като го хванете, трябва да го сравните с очакваната стойност, която искате да видите, че функцията произвежда в случай на успех.

Тогава вашето AppTest::test() може да изглежда по следния начин:

$actual = myForeach();
$this->assertEquals('my expected foreach return value', $actual);

Това е само за случая, когато myForeach изрично връща стойност (а във вашия случай не го прави умишлено или не). Сега, ако очаквате myForeach да изведе в конзолата, вместо изрично да върне някаква стойност (което може да бъде случай, ако TDD например CLI помощна програма), вашият тест ще изглежда така:

// Wrap your `myForeach` function into something special
// to catch its console output made with `print`
ob_start();
myForeach();
$actual = ob_get_clean();

// Now you have all your output from the function in $actual variable
// and you can assert with PHPUnit if it contains the expected string
$this->assertStringContainsString('my expected foreach return value', $actual);

Някои връзки: буфериране на PHP изход документи, наличен PHPUnit твърдения

person Valentine Shi    schedule 03.05.2020
comment
Не мога да използвам функцията, защото трябва да стартирам php app.php input.txt от терминала .. моля, насочете - person Selim Reza; 08.05.2020
comment
Опитах по твоя начин... проваля се със същия проблем -- имам нужда от макет за този. - person Selim Reza; 08.05.2020
comment
@SelimReza нямаш нужда от подигравка. Можете да използвате функция. Просто му предайте аргумента $list? С какъв конкретен проблем се проваля? - person Valentine Shi; 08.05.2020
comment
@SelimReza разделя горния фрагмент на 2 класа: Command ще приеме името на файла от CLI аргументи Calculator->execute(array $list) ще премине през съдържанието на файла и ще извика CalculatorAPI и ще постави резултатите напр. масив. След това върнете този масив. Тогава командният клас ще отпечата върнатия резултат. - person Valentine Shi; 08.05.2020
comment
@SelimReza сега към тестовете. Първият може да е CalculatorTest. Там тествате Calculator->execute($list) резултат. Можете да инжектирате фалшивия екземпляр на клас CalculatorAPI като този Calculator->execute(array $list, $calculatorAPI). Вие сами правите фалшификата. Просто създайте клас, който се преструва, че прави това, което истинският CalcualtorAPI трябва. Във вашите тестове вие ​​инжектирате фалшивия, във вашия Command клас вие инжектирате своя истински екземпляр от CalculatorAPI клас. - person Valentine Shi; 08.05.2020
comment
Актуализирах кода (моя въпрос) според вашите инструкции. моля, проверете и актуализирайте вашето решение, което ще ми помогне - person Selim Reza; 09.05.2020
comment
@SelimReza премахнете main( $inputData ) от горния кодов фрагмент. Това е виновникът защо вашият код се изпълнява на require_once време. Преработете вашата main функция, за да вземете 2 параметъра, които да съответстват на този ред в теста $result = main($this->data, $calAPI);. Също така, ако решението ви е да echo резултати в main вижте моя отговор, за да преработите теста си. Не можете да използвате $result = main($this->data, $calAPI);assignment, тъй като вашият main не връща нищо. - person Valentine Shi; 10.05.2020