gpt4 book ai didi

PHPUnit,在我对抽象类及其子类的测试中避免重复的正确方法

转载 作者:搜寻专家 更新时间:2023-10-31 21:11:09 24 4
gpt4 key购买 nike

我正在尝试遵循/学习 TDD。我正在使用 PHPUnit。目前,我正在编写非常简单的小类/项目,只是为了吸收所有内容。

目前我正在编写扑克牌设置。

因此,为了开始它,我编写了这个测试,因为我会避免在我的纸牌花色中重复,我决定测试应该针对花色可以扩展的抽象类。

当您读到文章结尾时,希望类的模式很明显。

BaseSuitTest.php

use Cards\French\Suits\BaseSuit as Card;

class BaseSuitTest extends PHPUnit_Framework_TestCase
{

protected $Card;

public function setUp()
{
$this->Card = $this->getMockForAbstractClass('Cards\French\Suits\BaseSuit', [10]);
}


/**
* @expectedException InvalidArgumentException
*/
public function testConstructThrowsExceptionIfFirstArgLessThan1()
{
$Card = $this->getMockForAbstractClass('Cards\French\Suits\BaseSuit', [0]);
}


/**
* @expectedException InvalidArgumentException
*/
public function testConstructThrowsExceptionIfFirstArgHigherThan13()
{
$Card = $this->getMockForAbstractClass('Cards\French\Suits\BaseSuit', [14]);
}


public function testGetSuitReturnsClassName()
{
$suit = $this->Card->getSuit();
$this->assertSame( get_class($this->Card), $suit);
}


public function testGetValueReturnsValue()
{
$value = $this->Card->getValue();
$this->assertSame(10, $value);
}
}

然后我写了下面的文件,让所有的测试都通过了。至于这一点,我也在考虑是否应该为 BaseSuit 实现一个 CardInterface(我应该编写一个测试来检查实现还是这不是测试的一部分)。我决定不这样做。

BaseSuit.php

namespace Cards\French\Suits;

abstract class BaseSuit
{

const MIN_VALUE = 1;
const MAX_VALUE = 13;


protected $value;


public function __construct($value)
{
if( $this->isWithinValueRange($value) === false)
throw new \InvalidArgumentException('The value must be higer than 0 and less than 14 (1-13) Given ' . $value);
$this->value = $value;
}


protected function isWithinValueRange($value)
{
if($value < self::MIN_VALUE OR $value > self::MAX_VALUE)
return false;
return true;
}


public function getSuit()
{
return get_class($this);
}


public function getValue()
{
return $this->value;
}
}

最后,我开始对将从基类扩展的实际类/套装进行测试。

该测试与 BaseSuit 中的测试非常相似,这已经让我心烦意乱。

HeartTest.php

use Cards\French\Suits\Heart as Heart;

class HeartTest extends PHPUnit_Framework_TestCase
{

protected $Heart;


public function setUp()
{
$this->Heart = new Heart(10);
}


/**
* @expectedException InvalidArgumentException
*/
public function testConstructThrowsExceptionIfFirstArgLessThan1()
{
$Heart = new Heart(0);
}


/**
* @expectedException InvalidArgumentException
*/
public function testConstructThrowsExceptionIfFirstArgHigherThan13()
{
$Heart = new Heart(14);
}


public function testGetSuitReturnsClassName()
{
$suit = $this->Heart->getSuit();
$this->assertSame( get_class($this->Heart), $suit);
}


public function testGetValueReturnsValue()
{
$value = $this->Heart->getValue();
$this->assertSame(10, $value);
}
}

我再次编写代码以便测试通过。

心.php

namespace Cards\French\Suits;

class Heart extends BaseSuit {}

所有测试都通过了,但还不是很酷。我想避免重复从 BaseSuit 延伸出来的套装测试(比如 Heart)。

我最初的想法是将 BaseSuit 中的方法重命名为 protected然后从这个测试延伸。这是其中一个 BaseSuit 的示例重命名测试。

BaseSuit.php中的重构方法

/**
* @expectedException InvalidArgumentException
*/
protected function constructThrowsExceptionIfFirstArgLessThan1($class)
{
// .. i have not written this code, it just a figment of my imagination.
}

这是我分开的地方。我不确定如何继续。

将 BaseSuitTest 中的测试移动到 protected 方法意味着我要么放弃当前的公共(public)测试方法。这可以修复我制作调用 protected 方法的新测试方法。

代码示例、重构建议、模式建议以及阅读本文时您脑海中浮现的任何建设性想法,我将非常感激。

有人建议我使用一个提供程序来运行以相同方法运行的测试。聪明,我以后会这样做,但我看不出这能如何解决我的情况。只是当它是抽象的 BaseSuit 时,我想在测试中使用 getMockForAbstract,当它是套装时,我只是应该更像 HeartTest。我需要帮助以了解如何以正确的方式实现。

最佳答案

我认为您没有达到 TDD 的主要目标。与其询问如何重构测试以避免代码和工作重复,不如使用测试来告知非测试代码的设计。为什么 Heart 是它自己的类?它改变或添加到 BaseSuit 的什么行为将不同于 SpadeDiamondClub

您已经将卡片的序号值变成了数据属性;你应该对西装做同样的事情。每张牌不是具有值(value)的花色,而是应该有花色和值(value)。这允许您拥有一个单一的、具体的 Card 类,而不需要基础或抽象版本。创建一个 Suits 类,它使用常量和排序所需的任何方法定义不同的花色 (尽管那些可能属于 Rules 类)。

如果您仍然发现需要对更复杂的西装进行建模,我会坚持使用具有 name 的单个通用 Suit 类symbolorder等作为数据属性。

关于PHPUnit,在我对抽象类及其子类的测试中避免重复的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19182198/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com