如何为使用Random的代码编写JUnit测试

时间:2014-04-23 15:51:16

标签: java junit

我有一个简单的错误方法,我想写一个JUnit语句来测试这是代码:

public static ArrayList union(ArrayList a, ArrayList b) {
    ArrayList d;        

    int randNum = (int) Math.random();

    // if random is dividable by 2 then a is return else b will.
    if (randNum % 2 == 0)
    {
        return a;
    }
    else
    {
        return b;
    }

}

这是问题,转换Math.random()不会产生整数随机数。因此,当调用该方法时,它将返回数组列表a。我想编写一个涵盖此声明的测试用例,并使其无法显示它未达到b。

目前我有这个测试用例:

@Test
public void testUnion_2() throws Exception {
    ArrayList a = new ArrayList();
    ArrayList b = new ArrayList();

    ArrayList result = SectionOne.union(a, b);

    // add additional test code here
    assertNotNull(result);
    assertEquals(0, result.size());
}

谢谢,我非常感谢你的帮助。

4 个答案:

答案 0 :(得分:1)

您应该将测试中的方法称为1000或10000次,并检查您在大约50%的时间内获得a

答案 1 :(得分:1)

您应该考虑重写方法以使其更易于测试,但与维护代码和测试的成本相比,测试此代码的好处很小。 p>

我建议您创建一个传递Random实例的方法版本:

static <E> List<E> pickOneAtRandom(List<E> a, List<E> b, Random random) {
  if (random.nextInt(2) == 0) {
     return a;
  }
  return b;
}


public static <E> List<E> pickOneAtRandom(List<E> a, List<E> b) {
  return pickOneAtRandom(a, b, new Random());
}

然后,您可以使用模拟框架测试第一个方法,或者使用硬编码种子传入Random实例。

(注意我重命名了方法; union对我意味着以某种方式合并两个列表)

您可以决定公开第一个方法(也许调用者想要使用SecureRandom)。

这种方法存在一些问题:

  1. 如果您使用模拟,最终会在测试中对实现进行硬编码
  2. 如果您使用具有常量种子的Random实例进行测试,则可能会导致测试因实现中的简单更改而中断。
  3. 其他人建议多次运行测试。多次测试该方法有一些问题:

    1. 它可以减慢您的测试运行
    2. 该测试只能证明可能在50%的时间内选择了第一个列表
    3. 就个人而言,我认为这段代码很简单,不需要测试。

答案 2 :(得分:0)

调用方法100次并计算结果a和b。由于您使用随机,因此您的测试最终只能使用a或b。因此,检查a和b计数器是否大于0.

答案 3 :(得分:0)

您可以使用支持mocking java system classes in newer versions的PowerMock等工具来更改对Math.random()的调用行为。

如果这样做,您可以测试方法代码的其余部分。但我认为重点是证明Math.random()永远不会提供满足“randNum%2!= 0”的结果。