6

パスワードを検証する次のメソッドがあります。

/**
 * Checks if the given password is valid.
 * 
 * @param password The password to validate.
 * @return {@code true} if the password is valid, {@code false} otherwise.
 */
public static boolean validatePassword(String password) {
    int len = password.length();
    if (len < 8 || len > 20)
        return false;
    boolean hasLetters = false;
    boolean hasDigits = false;
    for (int i=0; i<len; i++) {
        if (!Character.isLetterOrDigit(password.charAt(i)))
            return false;
        hasDigits = hasDigits || Character.isDigit(password.charAt(i));
        hasLetters = hasLetters || Character.isLetter(password.charAt(i));
    }
    return hasDigits && hasLetters;
}

循環的複雑度の数値に焦点を当てましょう:その値は何ですか?

メトリクス1.3.6は7だと言っていますが、7つの独立したパスを見つけることはできません。5つしか見つかりません。そして、ウィキペディアはあまり役に立ちませんでした。この式をどのように使用すると思いますπ - s + 2か?

2つifの出口点、1つforおよび3つの出口点がありますが、行き詰まっています。入口点を数える必要がありますか?if2つの条件があるので、最初に2回カウントする必要がありますか?

編集:

さて、Cyclomatic Numberが7であることがわかりました。これは、7つの独立したパスがあることを意味します。したがって、コードの100%をカバーする場合、7つの異なるテストケースを見つけることができるはずです。

さて、まだ最後のものが見つかりません!私はこれらを見つけました:

  1. 有効:asdf1234
  2. 短すぎる:asdf123
  3. 長すぎる:asdfsgihzasweruihioruldhgobaihgfuiosbhrbgtadfhsdrhuorhguozr
  4. 無効な文字:asdf * 123
  5. 全桁:12345678
  6. 数字なし:asdfghjk
  7. wtf ???
4

3 に答える 3

3

トリックは論理演算子が数えられることだと思います。

McCabe Cyclomatic ComplexityセクションのMetricsリンク(http://metrics.sourceforge.net/ )に基づいています。

1初期フロー

3つの決定ポイント(if、for、if)

3つの条件付き論理演算子(||、||、||)

合計:7

于 2013-03-13T17:26:07.893 に答える
2

ここで重要なのは、条件文が短絡を行うことだと思います。これは制御フローの一形態です。役立つのは、それを明示的にするためにコードを書き直すことです。この種の正規化は、プログラム分析を行うときに一般的です。一部のアドホック正規化(正式ではなく、マシンはこれを生成しませんが、ポイントを取得します)により、コードは次のようになります。

public static boolean validatePassword(String password) {
    int len = password.length();

    //evaluate 'len < 8 || len > 20'
    bool cond1 = len < 8;
    if (!cond1) cond1 = len > 20;
    //do the if test
    if (cond1)
        return false;

    boolean hasLetters = false;
    boolean hasDigits = false;
    //for loops are equivalent to while loops
    int i = 0;
    while(i < len) {
        if (!Character.isLetterOrDigit(password.charAt(i)))
            return false;

        //evaluate 'hasDigits || Character.isDigit(password.charAt(i))'
        bool hasDigitsVal = hasDigits;
        if (!hasDigitsVal) hasDigitsVal = Character.isDigit(password.charAt(i));
        //hasDigits = ...
        hasDigits = hasDigitsVal

        //evaluate 'hasLetters || Character.isLetter(password.charAt(i))'
        bool hasLettersVal = hasLetters;
        if (!hasLettersVal) hasLettersVal = Character.isLetter(password.charAt(i));
        //hasLetters = ...
        hasLetters = hasLettersVal;

        i++;
    }

    //evaluate 'hasDigits && hasLetters'
    bool cond2 = hasDigits;
    if (cond2) cond2 = hasLetters;
    //return ...
    return cond2;
}

||and&&演算子は、基本的にifコードにステートメントを追加するだけであることに注意してください。ifまた、6つのステートメントと1つのwhileループがあることに注意してください。多分それはあなたが探していた7ですか?


複数の出口点について、それは赤いニシンです。各関数は、関数の終わりである1つの出口ノードを持っていると見なします。複数のreturnステートメントがある場合、各returnステートメントはその出口ノードにエッジを描画します。

void foo() {
    if (cond1) return a;
    if (cond2) return b;
    return c;
}

グラフは次のようになります。ここで、は次-----val----> EXITの値で関数を終了することを意味しますval

START -> cond1 ------------------------a------------> EXIT
           |                                            |
         cond2 ------------------------b----------------+
           |                                            |
         return -----------------------c----------------|

コードを書き直す場合は、基本的に別の「プレリターン」ノードを追加して、出口ノードに移動します。

void foo() {
    int val;
    if (cond1) {
        val= a;
    }
    else {
        if (cond2) {
            val= b;
        }
        else {
            val= c;
        }
    }
    return val;
}

これで、次のようになります。

START -> cond1 ---> val=a --------------------------> return ----val----> EXIT
           |                                            |
         cond2 ---> val=b ------------------------------+
           |                                            |
           + -----> val=c ------------------------------+

それはまだ同じくらい複雑で、コードはただ醜いです。

于 2013-03-13T17:41:47.213 に答える
0

ここでうまく説明されているように:

循環的複雑度=(2 + ifs + loops + cases --return)ここで、

* ifs is the number of IF operators in the function,
* loops is the number of loops in the function,
* cases is the number of switch branches in the function (without default), and
* return is the number of return operators in the function.

すでに述べたように、論理条件も計算されます。

たとえばif (len < 8 || len > 20)、次の3つの条件としてカウントされます。

  1. if
  2. len<8
  3. len > 20

つまり、コードの複雑さは次の2 + 8 - 3 = 7ようになります。

  • 2-それは常にそこにあります(そこにある式を参照してください)
  • 8-ブランチの数
  • 3-返品数
于 2013-12-09T16:59:30.767 に答える