lundi 5 octobre 2020

PHPUnit tests isolation and how to write a test where expected value depends on some value in method that changes often

So I am coding in PHP and am writing tests with PHPUnit. I have this method convertCashAmountToMainCurrency that i want to test:

public static function convertCashAmountToMainCurrency(string $currency, float $amount): float
{
    $feeInMainCurrency = $amount / Constants::CURRENCIES[$currency][Constants::RATE];

    return self::roundUp($feeInMainCurrency, Constants::CURRENCIES[Constants::MAIN_CURRENCY][Constants::PRECISION]);
}

public static function roundUp(float $value, int $precision): float
{
    $pow = pow(10, $precision);

    return (ceil($pow * $value) + ceil($pow * $value - ceil($pow * $value))) / $pow;
}

And i have the Constants that are being used here:

public const RATE = 'RATE';
public const PRECISION = 'PRECISION';

public const CURRENCY_EUR = 'EUR';
public const CURRENCY_USD = 'USD';
public const CURRENCY_JPY = 'JPY';

public const MAIN_CURRENCY = self::CURRENCY_EUR;

public const CURRENCIES = [
    self::CURRENCY_EUR => [
        self::RATE => 1,
        self::PRECISION => 2,
    ],
    self::CURRENCY_USD => [
        self::RATE => 1.1497,
        self::PRECISION => 2,
    ],
    self::CURRENCY_JPY => [
        self::RATE => 129.53,
        self::PRECISION => 0,
    ],
];

I am testing the method like this:

/**
 * @param string $currency
 * @param float $amount
 * @param float $expectation
 *
 * @runInSeparateProcess
 * @preserveGlobalState disabled
 * @dataProvider dataProviderForConvertCashAmountToMainCurrencyTesting
 */
public function testConvertCashAmountToMainCurrency(string $currency, float $amount, float $expectation)
{
    $this->assertEquals(
        $expectation,
        Math::convertCashAmountToMainCurrency($currency, $amount)
    );
}

public function dataProviderForConvertCashAmountToMainCurrencyTesting(): array
{
    return [
        'convert EUR to main currency' => [Constants::CURRENCY_EUR, 100.01, 100.01],
        'convert USD to main currency' => [Constants::CURRENCY_USD, 100.01, 86.99],
        'convert JPY to main currency' => [Constants::CURRENCY_JPY, 10001, 77.21],
    ];
}

And the tests passes just fine when the expected value and the currency rate are stated in fixed size. But the problem is that i need them to pass every time, regardless of the currency convertion rate value, so i would not need to rewrite the tests every time the rate changes. Because now, if i change the RATE (or even the PRECISION, for instance) value, the tests will not pass due to assertion failure.

Since I was told that I need to isolate my tests to solve this issue, can anyone confirm this and get me on a right path with solving the issue? Thanks in advance for any help!

Aucun commentaire:

Enregistrer un commentaire