Pythonでの下限値と上限値のテスト

Sep 19 2020

コード機能

次のコードは、ユーザーが2つのプロパティの下限と上限に指定する値かどうかをテストします。

  1. 下限は上限よりも小さいです。
  2. 値が0より大きい(正)。

最初に下限が上限よりも小さいかどうかをチェックするため、下限が0より大きいかどうかをテストする場合は、上限が0より大きいことを暗黙的に検証します。したがって、私の考慮​​事項は次のとおりです。 「上限が0より大きいか」のチェックを省略してコンパクトにします。

コード

# Object getting labels
class Get_labels:
    def __init__(self,lower_bound,upper_bound,configuration_name):
        self.lower_bound = lower_bound
        self.upper_bound = upper_bound
        self.configuration_name = configuration_name
        self.check_threshold_validity()
          
                            
    # Verifies if the chosen thresholds are valid values.
    def check_threshold_validity(self):
        if self.lower_bound>=self.upper_bound:
            raise Exception(f'Sorry, the lower threshold={self.lower_bound} should be smaller than the upper bound={self.upper_bound} for configuration={self.configuration_name}')
        
        # checks if lower bound (and implicitly upper bound) are above zero
        if self.lower_bound<=0:
            raise Exception(f'Sorry, the lower threshold={self.lower_bound} should be larger than 0 for configuration={self.configuration_name}')
        
if __name__ == '__main__':
    get_labels = Get_labels(-1,25,"first")

デザインの選択

ただし、コードが変更された場合、暗黙的に行われるため、上限もチェックする必要があることが明らかでない場合があります。その結果、変更後に上限がゼロ未満のエッジケースがキャッチされない可能性があります。したがって、このシナリオを防ぐために、次のエラーが発生したかどうかを確認する2つの単体テストを実装できます。

  1. 下限が負、上限が負
  2. 下限ゼロ、上限負
  3. 下限は正、上限は負

質問

単体テストでテストされている場合でも、メインコードに明示的なチェックを含めることをお勧めしますか?

回答

9 FMc Sep 19 2020 at 00:38

異常な状況を除いて、クラスは物またはエンティティであり、したがってオブジェクトという用語ですが、関数またはメソッドはアクションまたは操作です。それに応じて名前を付けます。そのため、Get_labels奇妙な名前のクラスとして私を襲います。あなたが私たちに示したことに基づいて、私はBounds代わりに名前を提案するかもしれません。その名前の副次的な利点は、意味を失うことなく属性名を短縮できることです。

境界の基本的な妥当性をチェックするための別の方法は、チェックロジックがはるかに複雑になるか、コードの他の場所で使用されない限り、私には過剰に設計されているように見えます。したがって__init__()、この場合は単純な検証を行います。

コードでおしゃべりなメッセージや冗長なメッセージを使用したいという誘惑を避けてください。それは長期的にはあなたやあなたのユーザーを助けません-少なくともそれは私の経験です。物事を直接的かつ厳密に簡潔に保ちます。実際、メッセージを文体的な方向で自然なものではなく、非常に技術的なものに保つことがしばしば有益です。つまり、人間に対して口頭で問題を説明するのではなく(「下限は1000でしたが、上限は125である必要があります」)、説明したほうがよい場合がよくあります。公式、概略、コンピューターのような方法で問題。特に、このアプローチでは、アプリケーション内のすべてのエラーメッセージに従来の形式を採用できます。以下の書き直しに示されているエラーメッセージの形式は、一般的にはとして説明できますPROBLEM: SELF。一貫性のあるアプローチにより、最初に検証コードを記述し、それを長期間維持することが容易になります。一貫性はまた、ユーザーにプロ意識を伝えます。

これらの方針に沿って、__repr__()以下に示すように、最初にクラスを定義することで、このような検証メッセージの作成を簡素化できることがよくあります。

これまでの検証でValueErrorは、一般的なを上げるよりもaの方が適していExceptionます。また、他の種類のエラーをチェックすることを検討することもできます。たとえば、境界は整数のみに制限されていますか?

それを確認する場合は、を上げますTypeError。

最後に、文体的で確かに主観的な細かい点。以下は、記述されたコードからのスタックトレースです。詳細メッセージは、最初はf文字列として、次にパラメータが入力された状態で2回表示されます。これの何が問題になっていますか?深刻なことは何もありませんが、重くて退屈で、特定の優雅ささえ欠けています。少なくとも、詳細なメッセージの繰り返しは、ユーザーの気を散らすものであり、何が起こっているのかを理解するためにユーザーに視覚的または認知的負担をさらに増加させると言えます。これを、改訂されたコードのスタックトレースと比較してください。

# ORIGINAL.

Traceback (most recent call last):
  File "bounds.py", line 19, in <module>
    get_labels = Get_labels(-1,25,"first")
  File "bounds.py", line 7, in __init__
    self.check_threshold_validity()
  File "bounds.py", line 17, in check_threshold_validity
    raise Exception(f'Sorry, the lower threshold={self.lower_bound} should be larger than 0 for configuration={self.configuration_name}')
Exception: Sorry, the lower threshold=-1 should be larger than 0 for configuration=first

# REVISED.

Traceback (most recent call last):
  File "bounds.py", line 72, in <module>
    b1 = Bounds(1000, 125, 'first')
  File "bounds.py", line 67, in __init__
    raise Exception(msg)
Exception: Upper bound must be greater than lower: Bounds(1000, 125, first)

考慮すべきいくつかの可能な編集を含むコード:

class Bounds:

    def __init__(self, lower, upper, name):
        self.lower = lower
        self.upper = upper
        self.name = name

        if lower <= 0 or upper <= 0:
            msg = f'Bounds must be positive: {self}'
            raise ValueError(msg)

        if upper <= lower:
            msg = f'Upper bound must be greater than lower: {self}'
            raise ValueError(msg)

    def __repr__(self):
        return f'Bounds({self.lower}, {self.upper}, {self.name!r})'