【问题标题】:How to unit test function with some randomness如何以一些随机性对函数进行单元测试
【发布时间】:2013-09-12 05:14:58
【问题描述】:

我有一个函数,它返回 0 到 6 之间的三个随机元素数组。它确保所有元素不能具有相同的值(您可以有两个具有相同值的元素,但不能有三个)。以下是示例代码。

public function getRandom() {
    $array = array(0, 0, 0);
    do {
        $array[0] = rand(0, 6);
        $array[1] = rand(0, 6);
        $array[2] = rand(0, 6);
    } while(($array[0] == $array[1]) && ($array[0] == $array[2]));
    return $array;
}

我对单元测试有点陌生,我唯一能想到测试这个的是

  1. 测试此函数 1000 次,检查它是否返回 0 到 6 之间的数据,并且所有三个元素的值不能相同。
  2. 找到一种方法来覆盖函数 rand() 以便它返回我们想要的:
    • 返回值使所有三个元素具有相同的值,然后,返回具有相同值的两个元素的值。然后,返回具有不同值的所有元素的值。

我想知道是否有任何方法或者我的哪种方法更适合这种情况。

【问题讨论】:

标签: php unit-testing phpunit


【解决方案1】:

正如您猜对的那样,您无法真正可靠地测试随机性。

控制随机性的问题显示了您架构中的弱点:您有一个要测试的类和方法,但您无法控制在测试期间被调用的函数 (rand())。

一开始可能听起来很奇怪,但是如果你想用“受控”随机性进行测试,你需要以某种方式模拟随机函数,所以你需要一个 PHP 函数的包装器,它允许拦截调用并返回定义的测试测试期间的值。

想一想:如果您有一个具有随机方法的类,并且该类的一个实例被注入到您的测试类以提供随机值,您可以在测试期间模拟该对象并定义返回值。任务完成。 :)

现在实例化具有单个方法rand() 的单个对象听起来很奇怪,该方法将所有调用传递给同名的PHP 函数。更奇怪的是需要在运行时将该对象传递给测试类以使其工作。但是您不必具有该运行时依赖项。您还可以重构您的测试类,以查看是否注入了随机提供程序并使用它,如果没有,则直接使用rand()

如果你想对你的类进行更少的修改,有一个技巧可以覆盖内置的 PHP 函数:如果你的类在命名空间内并调用原生 PHP 函数,则首先在该命名空间内搜索该函数。如果你在测试文件中声明一个名为rand() 的函数与被测类在同一个命名空间中,那么该类将调用命名空间函数而不是 PHP 函数。然后您只需要考虑如何预定义该模拟函数的返回值,但您可能会使用一个全局变量或测试用例类的静态属性,其中填充了预定义的“随机性”:

namespace MyNameSpace;
function rand() {
    return array_shift(RandomTest::$randomValues);
}

class RandomTest extends PHPUnit_Framework_TestCase {
    public static $randomValues = array();
    public function testSomeRandomness() {
        self::$randomValues = array(0,0,0,0,1,2);
        // ... test 
    }
}

如果我有这份工作,我会选择真正的 PHPUnit 模拟对象,一个将其注入类的 setter,并将其编码为默认调用 rand() 的可选依赖项。

【讨论】:

    【解决方案2】:

    第二种方案确实是最好的;当然,这需要为要存根的 rand 函数创建某种接口。

    如果无法更改代码(即第三方代码),则第一个解决方案是唯一可能的解决方案。请记住,单元测试应该很快,而大量的迭代对此无济于事。

    作为第三个选项,您可以使用所谓的详尽测试:使用每个可能的值并进行单元测试来测试值的所有组合,即 [0, 0, 0], [0, 0, 1] ... 直到[5、5、5]。这意味着 6^3 = 216 个单元测试,但您可以确定所有组合都经过测试并且比解决方案 1 更好。

    【讨论】:

      猜你喜欢
      • 2021-01-16
      • 2019-04-15
      • 1970-01-01
      • 2023-01-30
      • 1970-01-01
      • 2014-02-08
      • 2012-07-18
      • 2010-09-10
      • 1970-01-01
      相关资源
      最近更新 更多