【问题标题】:Unit test mocking - doesnt make sense for me单元测试模拟 - 对我来说没有意义
【发布时间】:2013-03-20 06:39:41
【问题描述】:

我正在尝试学习单元测试,但遇到以下情况,我无法理解:

  1. 我有一个模型:SalesOrder - 为电子商务商店中的订单建模
  2. SalesOrder 有一个名为 gift_message_id 的属性
  3. 礼品消息 ID 是一个整数值,是 GiftMessage 模型的外键
  4. GiftMessage 模型有一个方法可以接受订单模型并根据 SalesOrder 正确加载 GiftMessage 实例。

我正在尝试编写一个准确测试此行为的测试,但我最终得到了 2 个模拟:1 个用于 SalesOrder,1 个用于 GiftMessage,它没有意义。我在这里做错了什么?

我尝试测试的方法如下所示:

public function loadGiftMessageByOrderModel(SalesOrder $order)
{
    $giftMessageId = $order->getGiftMessageId();

    //if the order has a gift message id then load the gift message model and return it
    if ($giftMessageId !== false) {
        return new GiftMessage($giftMessageId);
    }
    return false;
}

如何进行单元测试,记住订单和礼物消息数据存储在数据库中。

【问题讨论】:

  • 我同意,单元测试是个笑话
  • 我认为它很有价值 - 但我只是无法弄清楚如何做到这一点并使测试变得有价值
  • 说实话,我不太了解您的描述以及您想要测试的具体内容。一般来说,如果你想测试 X 类,你可以模拟或实例化所有外部实体,不管它们有多少。当然,在这里保持松散耦合是一个优势。
  • 我想测试一下,如果订单有礼物消息 id,则返回礼物消息模型,否则返回 false。我可以轻松地模拟 SalesOrder 模型以返回礼品消息 ID。我无法解决的问题是从该 id 加载一个新的 GiftMessage 并返回它。这是因为 GiftMessage 构造函数需要一个 id 并从数据库中加载它
  • 如何将数据库连接传递给GiftMessage 对象?你在这里有一些全局状态,这使得你的系统很难被测试并且可能真的有问题。

标签: php unit-testing junit mocking phpunit


【解决方案1】:

当您编写了loadGiftMessageByOrderModel 函数并解释了 GiftMessage 构造函数时,我认为您不能轻松地对这段代码进行单元测试。为了干净地测试它,您需要以 不是 构造函数的方法从数据库中加载 GiftMessage。您的构造函数不应调用与数据库交互的方法。另一个类或方法应该执行该加载,然后调用构造函数。大致是这样的:

public function loadGiftMessageByOrderModel(SalesOrder $order)
{
    $giftMessageId = $order->getGiftMessageId();

    //if the order has a gift message id then load the gift message model and return it
    if ($giftMessageId !== false) {
        // $giftMessageLoader handles loading from the DB; it doesn't create a GiftMessage object
        $giftMessageRecord = $giftMessageLoader.loadById( $giftMessageId );
        // $giftMessageFactory actually calls the constructor to create a GiftMessage
        return $giftMessageFactory.createFromRecord( $giftMessageRecord );
    }
    return false;
}

然后,您可以模拟 $giftMessageLoader.loadById 调用,以便控制从数据库返回的内容。您还可以测试$giftMessageFactory 是否正确调用GiftMessage 构造函数并创建正确的对象。

这里的总体教训是构造函数应该很简单。它们可以验证参数以便正确构造对象,但它们可能不应该调用应用程序的其他重要部分。

【讨论】:

    【解决方案2】:

    任何时候你有一个调用构造函数的方法并且在构造函数中完成了重要的工作,你就有麻烦了。我从上面看到的最好的选择是让上面的类拥有一个GiftMessageFactory 实例。然后,您可以模拟工厂以验证是否使用适当的值和适当的时间调用它。

    【讨论】:

      猜你喜欢
      • 2015-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多