首页 > 解决方案 > 如何在 Java 中创建单元测试?

问题描述

我有一个 java 类,它接受一个数字数组和一个相应概率数组,并充当一个随机数生成器,它根据另一个定义的相应概率从数组中返回一个数字。如何编写最少但有效的单元测试集?

class RandomGen {

    private int[] randomNums;
    private float[] probabilities;
    private float[] total_prob;

    RandomGen(int[] randomNums, float[] probabilites) throws Exception {
        if (this.set_arrays(randomNums, probabilites));
        else {
            throw new Exception("Invalid array format");
        }
    }

    private boolean set_arrays(int[] randomNums, float[] probabilities) {
        if (check_arrays(randomNums, probabilities)) {
            this.randomNums = randomNums;
            this.probabilities = probabilities;
            this.total_prob = new float[this.probabilities.length];

            total_prob[0] = probabilities[0];
            for (int i = 1; i < probabilities.length; i++){
                total_prob[i] = total_prob[i-1] + probabilities[i];
            }
            return true;
        }
        return false;
    }

    public int[] return_randomNums() {
        return this.randomNums;
    }

    public float[] return_probabilites() {
        return this.probabilities;
    }

    private boolean check_arrays(int[] randomNums, float[] probabilities) {
        float total_prob = 0;
        for (int i = 0; i < probabilities.length; i++) {
            if (probabilities[i] < 0) return false;
            total_prob += probabilities[i];
        }
        if (randomNums.length != probabilities.length || total_prob != 1) return false;
        return true;
    }

    public int nextNum() {
        float random = (float) Math.random();
        if (random <= total_prob[0]) {
            return randomNums[0];
        }
        for (int i=1; i < total_prob.length; i++) {
            if (total_prob[i-1] < random  && random <= total_prob[i]) return randomNums[i];
        }
        return 0;
    }
}

标签: javaunit-testingclasstesting

解决方案


对于学习单元测试,这个类可能有点太复杂了。我们也可以在这里只触及表面,因为这不是你可以从几个例子中学到的。我敦促你买一本关于这个主题的书。

但是既然我们已经到了,让我们看看你的课。

您的类的公共接口由构造函数nextNum()和两个 getter 组成(只返回字段的方法称为 getter,因为它们通常命名为getFieldName(),例如getRandomNums())。

getter 不包含任何逻辑。因此,我会避免测试它们。

您的构造函数实际上做了很多工作。首先,它检查数组是否有效(长度相同且概率加起来为 1),然后存储数组并使用累积概率构建一个新数组。为了测试它,每个测试用例都会创建一个新的实例,RandomGen其中包含不同的数组,这些数组构成不同的情况。显而易见的三种情况是:

  • 概率加起来为一,但两个数组的长度不同
  • 两个数组的长度相同,但概率数组元素的和不等于 1
  • 两个数组的长度相同,概率加起来为 1

前两种情况是错误情况,预计会引发异常,最后一种情况是“阳光情况”,您可以在其中检查您的 getter 现在是否返回了两个数组。累积概率 ( total_prob) 只能通过使用 来观察nextNum()

然后是nextNum()方法。这已经有点高级了,因为你无法预测Math.random(). 可能的解决方案是使用预定义的种子(正如 Victor Polo De Gyves Montero 建议的那样)或 wrap and injection Math.random()。在您的情况下,我会跳过它并首先阅读一本书并获得一些单元测试经验。


推荐阅读