测试这个的最佳方法是什么? 4位二进制数

What is the best way to test this? Binary digits with 4 positions

考虑网络表面上的 4 个输入字段 A、B、C 和 D。用户可以任意填充这些。如何填写这些字段有 16 种组合。允许的是:

A B C D
-------
1 0 0 0
1 1 0 0
1 1 1 0
1 1 1 1

其中 1 表示 not null,0 表示 null

我在 jsf 中使用 MVC 模式。我不希望逻辑在视图中,而是在控制器中。在 Java 中检查此内容的最佳方法是什么?

到目前为止我实施了两个解决方案:

解决方案 1:

@Override
public boolean isInputInvalid(Integer a, Integer b, Integer c, Integer d) {
    if (isNotSet(a) && isNotSet(b) && isNotSet(c) && isNotSet(d) {
        return true;
    }
    return (firstParameterDoesNotExistAndSecondDoesExist(a, b)) || (firstParameterDoesNotExistAndSecondDoesExist(b, c)) || (firstParameterDoesNotExistAndSecondDoesExist(c, d));
}

private boolean firstParameterDoesNotExistAndSecondDoesExist(Integer firstParameter, Integer secondParameter) {
    return isNotSet(firstParameter) && !isNotSet(secondParameter);
}

private boolean isNotSet(Integer parameter) {
    return parameter == null;
}

解决方案 2:

public boolean isInputValid(Integer a, Integer b, Integer c, Integer d) {
    if (exists(a) && !exists(b) && !exists(c) && !exists(d) || //
            exists(a) && exists(b) && !exists(c) && !exists(d) || //
            exists(a) && exists(b) && exists(c) && !exists(d) || //
            exists(a) && exists(b) && exists(c) && exists(d)) {
        return true;
    }
    return false;
}

private boolean exists(Integer level) {
    return level != null;
}

注:

第一种方法检查输入是否无效,而第二种方法检查输入是否有效(注意方法的名称) .

我写了 16 个单元测试用例,两个版本都 运行 绿色。

关于如何使代码更具可读性,您有什么hints/tips/tricks吗?

您可以使用二维数组创建图案。 优点是易于调整,并向其添加附加信息。 这是您的条件的一个小例子。 最后你只需要阅读在静态块中初始化的模式,这很容易阅读。

// Every boolean array in a dimension represents a valid pattern 
private static boolean[][] pattern;

static {
    pattern = new boolean[4][4];
    pattern[0] = new boolean[]{true, false, false, false};
    pattern[1] = new boolean[]{true, true,  false, false};
    pattern[2] = new boolean[]{true, true,  true,  false};
    pattern[3] = new boolean[]{true, true,  true,  true};
}

public static void main(String[] args) {
    // Testing an invalid combination
    System.out.println(test(new Integer[]{1,null,3,null}));
    // Testing a valid combination
    System.out.println(test(new Integer[]{1,2,3,null}));
}

private static boolean test(Integer[] input) {
    // cast the input to a boolean array that can be compared to the pattern.
    boolean[] arr = createArr(input);
    for(int i = 0;i<pattern.length;++i) {
        if(Arrays.equals(pattern[i], arr)) { // Check if the pattern exists in the list of valid pattern. If it exists, then this is a valid combination
            return true;
        }
    }
    // the loop never found a valid combination, hence it returns false.
    return false;
}

// This is just a helping method to create a boolean array out of an int array. It casts null to true and !null to false.
private static boolean[] createArr(Integer[] input) {
    boolean[] output = new boolean[input.length];
    for(int i = 0;i<input.length; ++i) {
        output[i] = input[i] != null;
    }
    return output;
}

要解决任意数量参数的问题,请在此处传入 truefalse(如果不是 null / null):

static boolean isValid(boolean... params) {
    boolean set = true;
    for (boolean param : params) {
        if (!set && param) return false;
        set = param;
    }
    return params[0];
}

或者更酷(并且恕我直言可读),但性能较低,在数组的 toString():

上使用正则表达式
static boolean isValid(boolean... params) {
    return Arrays.toString(params).matches("\[true(, true)*(, false)*]");
}

无论你使用哪种实现,你都会这样称呼它:

if (isValid(a != null, b != null, c != null, d != null))

Valid combinations are: 1000, 1100, 1110 and 1111

如果您只关心可读性:

public static List<String> validOptions = Arrays.asList("1000","1100","1110","1111");

public boolean isValid(Integer a, Integer b, Integer c, Integer d)
{
    StringBuilder sb = new StringBuilder();
    sb.append(a==null ? 0 : 1); 
    sb.append(b==null ? 0 : 1), 
    sb.append(c==null ? 0 : 1); 
    sb.append(d==null ? 0 : 1);
    return validOptions.contains(sb.toString());
}

请注意,这不是最快或最干净的解决方案(浪费一些 CPU 和内存)

另一种解决方案。涉及更多代码,但对我来说更容易理解:

boolean isInputInvalid(Object ... args) {
    int notNullDataIndex = -1;
    for (int i = args.length - 1; i >= 0; i--) {
        if (args[i] != null) {
            notNullDataIndex = i;
            break;
        }
    }
    if (notNullDataIndex < 0) return false;
    for (int i = notNullDataIndex; i >= 0; i--) {
        if (args[i] == null) return false;
    }
    return true;
}

不花哨但又快又简单:

static boolean isValid(boolean a, boolean b, boolean c, boolean d) {
    return a && (b || !c) && (c || !d);
}

通话:

isValid(a != null, b != null, c != null, d != null);

我真的不明白你为什么需要这个。比起测试输入是否有效的方法,首先只允许有效输入会好得多。

// This method is private, so you can't call it with arbitrary arguments.
private void privateMethod(Integer a, Integer b, Integer c, Integer d) {
    // do something();
}

public void method(int a) {
    privateMethod(a, null, null, null);
}

public void method(int a, int b) {
    privateMethod(a, b, null, null);
}

public void method(int a, int b, int c) {
    privateMethod(a, b, c, null);
}

public void method(int a, int b, int c, int d) {
    privateMethod(a, b, c, d);
}

将此修改为任意数量的参数(不仅仅是 4 个)的方法是使用带有签名的方法

public void method(int... a)

那么,如果传入的数组长度小于要求的长度,剩下的输入只用null即可。

如果这不能解决您的问题,我认为您应该考虑编辑您的问题以举例说明您的用例,因为我怀疑有更好的方法可以实现您的要求。