PHP单元测试方法

PHP单元测试方法,php,unit-testing,phpunit,Php,Unit Testing,Phpunit,请看下面的代码。我们有一个类FightService,它实现了两个英雄之间战斗的逻辑。战斗结束后,其中一位英雄可能会失去一些生命值 如何以正确的方式实现FightService::fight()方法的测试 如果您认为需要,可以随意重构任何代码 使用PHPUnit\Framework\TestCase; 接口接口 { 公共函数getAttack():int; 公共函数getDefense():int; 公共函数getHealthPoints():int; 公共功能设置健康点(int$healthP

请看下面的代码。我们有一个类FightService,它实现了两个英雄之间战斗的逻辑。战斗结束后,其中一位英雄可能会失去一些生命值

如何以正确的方式实现
FightService::fight()
方法的测试

如果您认为需要,可以随意重构任何代码

使用PHPUnit\Framework\TestCase;
接口接口
{
公共函数getAttack():int;
公共函数getDefense():int;
公共函数getHealthPoints():int;
公共功能设置健康点(int$healthPoints);
}
类损伤计算器
{
恒损系数=0.2;
公共静态函数CalculatedImage(英雄界面$攻击者,英雄界面$defender):int
{
$damage=0;
如果($attacker->getAttack()>$defender->getDefence()){
$baseDamage=$attacker->getAttack()-$defender->getDefence();
$factor=$baseDamage*self::损害系数;
$minDamage=$baseDamage-$factor;
$maxDamage=$baseDamage+$factor;
$damage=mt_rand($minDamage,$maxDamage);
}
退还$damage;
}
}
阶级斗争服务
{
公共功能战斗(英雄界面$攻击者,英雄界面$防御者)
{
$damage=DamageCalculator::calculateDamage($attacker,$defender);
$defender->setHealthPoints($defender->getHealthPoints()-$damage);
}
}
类FightServiceTest扩展了TestCase{
公共函数testFight()
{
//这里是我的测试,但不工作,我无法将参数传递到接口,所以我不确定我在做什么?
$playerOne=兰特(1100);
$playerTwo=兰特(1100);
$this->assertInstanceOf(
FightService::类,
战斗服务::战斗($playerOne,$playerTwo)
);
}
}

静态调用是固定的依赖项,应该避免。如果使用依赖项注入,则可以使用存根和/或模拟替换依赖项

因此,DamageCalculator也可以作为一个接口,并允许不同的实现

use PHPUnit\Framework\TestCase;

interface HeroInterface {
  public function getAttack(): int;

  public function getDefence(): int;

  public function getHealthPoints(): int;

  public function setHealthPoints(int $healthPoints);
}

interface DamageCalculatorInterface {

  public function calculateDamage(HeroInterface $attacker, HeroInterface $defender): int;
}

class FightService {
  /**
   * @var DamageCalculatorInterface
   */
  private $_damageCalculator;

  public function __construct(DamageCalculatorInterface $damageCalculator) {
    $this->_damageCalculator = $damageCalculator;
  }

  public function fight(HeroInterface $attacker, HeroInterface $defender) {
    $damage = $this->_damageCalculator->calculateDamage($attacker, $defender);

    $defender->setHealthPoints($defender->getHealthPoints() - $damage);
  }
}

class FightServiceTest extends TestCase {

  public function testFight(): void {
    $attacker = $this->createMock(HeroInterface::class);
    $defender = $this->createMock(HeroInterface::class);
    $defender
      ->expects($this->once())
      ->method('getHealthPoints')
      ->willReturn(21);
    $defender
      ->expects($this->once())
      ->method('setHealthPoints')
      ->with(16);

    $damageCalculator = $this->createMock(DamageCalculatorInterface::class);
    $damageCalculator
      ->expects($this->once())
      ->method('calculateDamage')
      ->with($attacker, $defender)
      ->willReturn(5);

    $fightService = new FightService($damageCalculator);
    $fightService->fight($attacker, $defender);
  }
}

无法将参数传递给接口。您需要创建一个
实现
此接口的类,并创建该类的对象以在测试中使用:类Hero实现HeroInterface(){public function getAttack():int{//add some code}public function getDefense():int{//add some code}public function getHealthPoints():int{//add some code}公共函数setHealthPoints(int$healthPoints){//add some code}
如果您认为有必要,可以随意重构任何代码。
是的,您可以通过模拟接口来避免创建新类:。但我认为首先您应该进行一个测试,该测试可以正常工作,并用一个类回答问题,然后在删除该类后再尝试进一步。非常棒的thx duo,这个有趣的公共函数testF呢ight(HeroInterface$interface){//实现测试$rand=rand(1100);$interface->getAttack($rand);$interface->GetDefense($rand);$interface->getHealthPoints($rand);$this->assertInstanceOf(FightService::fight());}