2011-02-09 13 views
5

OK、序文として、この質問は私の通常レベルの質問よりも潜在的に「愚かです」 - この問題は最後の数日間私を迷惑にしていましたので、とにかく尋ねます。私は私の問題が何であるかを模擬的に説明しますので、現在の問題に一般化することができます。これが実行されたときPerl、文字列、浮動小数点、ユニットテストと正規表現!

#!/usr/bin/perl -w use strict; 

use Test::More 'no_plan'; 

my $fruit_string = 'Apples cost $1.50'; 
my ($fruit, $price) = $fruit_string =~ /(\w+)s cost \$(\d+\.\d+)/; 

# $price += 0; # Uncomment for Great Success 
is ($price, 1.50, 'Great Success'); 

は今、私はメッセージ

# Failed test 'Great Success' 
#   got: '1.50' 
#  expected: '1.5' 

は、テスト作業を行うために取得する - 私はどちらかのコメント行のコメントを解除、またはis ($price, '1.50', 'Great Success')を使用しています。どちらのオプションも私のためには機能しません。Test :: Deepとcmp_deeplyを使って膨大な量のネストされたデータをテストしています。私の質問は、どのように正規表現から二重を抽出し、二重としてすぐに使うことができるのか、あるいはもっと良い方法があれば教えてください。ハード。数として解釈される

+0

文字列と数値を比較するので、文字列として比較されます。私はあなたがそれで何かをすることができるとは思わない。 –

答えて

10

として解釈されますが、まだあなたは、単ににnum()ラッパーを使用することができますTest::Deep,を使用しています文字列の比較ではなく数値を実行します(2つの不正確な浮動小数点値を比較するために許容範囲内に追加することもできます)。

cmp_deeply(
    $result, 
    { 
     foo   => 'foo', 
     bar   => 'blah', 
     quantity => 3, 
     price  => num(1.5), 
    }, 
    'result hash is correct', 
); 

通常の比較の場合は、cmp_okが有効ですが、num()は引き続き使用できます。cmp_deeply($value, num(1.5), 'test name')はまだ動作しています。

+1

まさに私が探していたものです、ありがとうございました。 –

1

フォース$price

is (0 + $price, 1.50, 'Great Success'); 
+2

@Platinum Azure:いいえ、あなたは本当に番号を追加する必要があります。試して。 – btilly

+0

うん、私はちょうど確かめるためにパーラップをもう一度見て、あなたは正しい。たぶん私はPerl 6か何かを考えているかもしれません。 –

+1

私の記事で述べたように、私はcmp_deeplyを使用しているので、0 + $ priceを効果的に使うことはできません。0 + $ priceを行うには、現在のコード全体を調べて、ダブルでなければなりません。 –

0

この現象の理由は、その引数の文字列化を強制され、比較を行うためにeqを使うです。 1.50が '1.5'にストリングし、これは失敗します。

あなたが選択するのは、行動(強制的な文字列または数字)を使用することです。そうでなければ数値に比較して数値的に比較します。私は個人的に後者のアプローチに行きます。

1

okを試してみませんか? isがあまりにも微妙なことや賢いことをしているのかどうかを心配する必要はなく、実際にテストすることをテストすることになります。

ok($price == 1.5, 'Great Success'); 

isが失敗した場合に、いくつかの追加の診断を提供していますが、それはあまりにも、

ok($price == 1.5, 'Great Success') or diag("Expected \$price==1.5, got $price"); 
+1

'は、' ok'ができないアサーションに失敗した場合に、期待値と与えられた値を供給します。 – Tim

1

is($x, $y, $name)cmp_ok($x, 'eq', $y, $name)と同等であるため、あなたのテストが失敗しているokを行うのに十分に簡単です。 eqは、それぞれの引数が文字列として評価されるようにします。数値の等価が必要なので、'=='を使用してcmp_okで書き出すことができます。あなたはisの独自の数値バージョン書き込むことによって、物事を簡単にすることができます:

sub is_num {cmp_ok $_[0], '==', $_[1], $_[2]} 

をしかし、そのバージョンが微妙に壊れている、それは間違った行にエラーを報告します。エラー報告は、右の行を示していることを確認するには:cmp_okは、エラーが起こった場所を決定するcallerを使用しているため、goto &subため

sub is_num {splice @_, 1, 0, '=='; goto &cmp_ok} 

理由があります。 goto &sub構文では、is_numのコールフレーム設定が消去され、cmp_okは、is_numの場所から呼び出されたと考えられます。

最後に、Test::Moreのためのシンタックスシュガーを提供し、私のモジュールTest::Magicのプラグ:

use Test::Magic 'no_plan'; 

... # setup code 

test 'fruit price', 
    is $price == 1.50; 

cmp_ok($price, '==', 1.50, 'fruit price')

+0

'goto'の代わりに' local $ Test :: Builder :: Level = $ Test :: Builder :: Level + 1; 'を実行して、失敗したテストがどこに報告されるかを変更するべきです。 – Ether

+0

@Ether => Perlが透過的にディスパッチする汎用の方法を提供する場合、なぜAPI固有のソリューションを使用するのですか? '$ Test :: Builder :: Level'の設定が必要な状況がいくつかあります(一つの呼び出しサイトから複数のテストを実行したり、テスト後のアクションを実行しています)。しかし、これは一つではありません。 –

関連する問題