Обзор моей модульного тестирования (в PHP)


В конце этой недели, я наконец нашел немного времени, чтобы узнать модульного тестирования (речь идет о времени, я знаю).
Так что я пытался сделать это в PHP, с помощью PHPUnit 3.6.

Я написал небольшой, простой и бесполезный класс-оболочку для файлов, и базового модульного тестирования класса для это.
Как я сам ученик, и вокруг меня никто не может помочь мне о том, что, возможно, для кого-то, чтобы рассмотреть его, и скажите мне, что правильно и что неправильно, и как я могу улучшить мои тесты?

Qyy.G.en.PHP.File/Qyy_G_en_File.php:

// TODO: doc
class Qyy_G_en_File
{  
  protected $filename;

  // TODO: doc
  function __construct ($filename)
  {
    if (!file_exists($filename))
    {
      throw new InvalidArgumentException(
        'This file does not exist or permissions are not set correctly: '
          .$filename,
        404);
    }

    $this->filename = $filename;
  }

  // TODO: doc
  public function GetFilename ()
  {
    return $this->filename;
  }

  // TODO: doc
  // http://php.net/manual/en/function.basename.php
  public function GetBasename ()
  {
    return basename($this->GetFilename());
  }

  // TODO: doc
  // http://php.net/manual/en/function.pathinfo.php
  public function GetBasenameNoSuffix ()
  {
    $return = pathinfo($this->GetFilename(), PATHINFO_FILENAME);

    if (is_null($return) || empty($return))
    {
      throw new LengthException('This file seems to start with a dot.', 404);
    }

    return $return;
  }

  // TODO: doc
  // http://php.net/manual/en/function.pathinfo.php
  public function GetSuffix ()
  {
    $return = pathinfo($this->GetFilename(), PATHINFO_EXTENSION);

    if (is_null($return) || empty($return))
    {
      throw new LengthException('There is no suffix for this file.', 404);
    }

    return $return;
  }

  // TODO: doc
  // http://php.net/manual/en/function.dirname.php
  public function GetDirname ()
  {
    return dirname($this->GetFilename());
  }

  // TODO: doc
  // http://php.net/manual/en/function.realpath.php
  public function GetRealpath ()
  {
    $return = realpath($this->GetFilename());

    if ($return === false)
    {
      $lastError = error_get_last();

      throw new Exception(
        'Unable to determine the real path. '
          .'It might be due to a lack of permissions.',
        403  ,
        new Exception(
          'message: "'.$lastError['message'].'"'.PHP_EOL
            .'file: "'.$lastError['file'].'"'.PHP_EOL
            .'line: `'.$lastError['line'].'`'.PHP_EOL,
          $derniereErreur['type']));
    }

    return $return;
  }
}

Qyy.G.en.PHP.File/UnitTests/Qyy_G_en_FileTest.php:

require_once dirname(__FILE__) . '/../Qyy_G_en_File.php';

/**
 * Test class for Qyy_G_en_File.
 */
class Qyy_G_en_FileTest extends PHPUnit_Framework_TestCase
{

  /**
   * @var Qyy_G_en_File
   */
  protected $object0;

  /**
   * @var Qyy_G_en_File
   */
  protected $object1;

  /**
   * @var Qyy_G_en_File
   */
  protected $object2;

  /**
   * @var array
   */
  protected $filenames;

  /**
   * Sets up the fixture.
   */
  protected function setUp()
  {
    $this->filenames = array(
      '../readme.md',
      '../.gitignore',
      '../README',
      'foo.bar');

    $this->testNewObject0();
    $this->testNewObject1();
    $this->testNewObject2();
  }

  public function testNewObject0 ()
  {
    $this->object0 = new Qyy_G_en_File($this->filenames[0]);

    $this->assertEquals(true, is_a($this->object0, 'Qyy_G_en_File'));
  }

  public function testNewObject1 ()
  {
    $this->object1 = new Qyy_G_en_File($this->filenames[1]);

    $this->assertEquals(true, is_a($this->object1, 'Qyy_G_en_File'));
  }

  public function testNewObject2 ()
  {
    $this->object2 = new Qyy_G_en_File($this->filenames[2]);

    $this->assertEquals(true, is_a($this->object2, 'Qyy_G_en_File'));
  }

  /**
   * @expectedException InvalidArgumentException
   */
  public function testNewObject3 ()
  {
    new Qyy_G_en_File($this->filenames[3]);
  }

  /**
   * @depends testNewObject0
   * @depends testNewObject1
   * @depends testNewObject2
   */
  public function testGetFilename()
  {
    for($i = 0; $i <= 2; $i++)
    {
      $this->assertEquals(
        $this->filenames[$i],
        $this->{'object'.$i}->GetFilename());
    }
  }

  /**
   * @depends testNewObject0
   * @depends testNewObject1
   * @depends testNewObject2
   */
  public function testGetBasename()
  {
    for($i = 0; $i <= 2; $i++)
    {
      $this->assertEquals(
        basename($this->filenames[$i]),
        $this->{'object'.$i}->GetBasename());
    }
  }

  /**
   * @depends testNewObject0
   */
  public function testGetBasenameNoSuffix0 ()
  {
    $this->assertEquals('readme', $this->object0->GetBasenameNoSuffix());
  }

  /**
  * @depends testNewObject1
  * @expectedException LengthException
  */
  public function testGetBasenameNoSuffix1 ()
  {
    $this->object1->GetBasenameNoSuffix();
  }

  /**
   * @depends testNewObject2
   */
  public function testGetBasenameNoSuffix2 ()
  {
    $this->assertEquals('README', $this->object2->GetBasenameNoSuffix());
  }

  /**
   * @depends testNewObject0
   */
  public function testGetSuffix0 ()
  {
    $this->assertEquals('md', $this->object0->GetSuffix());
  }

  /**
   * @depends testNewObject1
   */
  public function testGetSuffix1 ()
  {
    $this->assertEquals('gitignore', $this->object1->GetSuffix());
  }

  /**
   * @depends testNewObject2
   * @expectedException LengthException
   */
  public function testGetSuffix2 ()
  {
    $this->object2->GetSuffix();
  }

  /**
   * @depends testNewObject0
   * @depends testNewObject1
   * @depends testNewObject2
   */
  public function testGetDirname ()
  {
    for($i = 0; $i <= 2; $i++)
    {
      $this->assertEquals(
        dirname($this->filenames[$i]),
        $this->{'object'.$i}->GetDirname());
    }
  }

  /**
   * @depends testNewObject0
   * @depends testNewObject1
   * @depends testNewObject2
   */
  public function testGetRealpath ()
  {
    for($i = 0; $i <= 2; $i++)
    {
      $this->assertEquals(
        realpath($this->filenames[$i]),
        $this->{'object'.$i}->GetRealpath());
    }
  }
}


259
4
задан 3 октября 2011 в 07:10 Источник Поделиться
Комментарии
1 ответ

В целом, похоже, вы прочь к большому началу. Я собираюсь пропустить вокруг немного, в чем, однако, я рекомендую есть определенно несколько вещей, которые могли быть очищены.

public function testNewObject3 ()
{
// I'm not sure you can define what the exception should
// describe in the doc-block however you can by using the method
$this->setExpectedException('InvalidArgumentException', 'File does not exist');
new Qyy_G_en_File($this->_getNonExistantFile());
}

// I would use something like this to describe a bit more of what the filename means
private function _getNonExistantFile()
{
return 'Foo.bar';
}

В Setup() метод, вы называете ряд других тестов для подготовки будущих тестов. С модульного тестирования, вы хотите сохранить отдельные тесты. В ваш код, если testNewObject2() завершается неудачей, testGetSuffix1() также не будет работать, хотя это не имеет отношения.

Чтобы сократить дублирование кода, использовать частные методы для определенных нужд. Может, что-то вроде этого:

public function testNewObjectWithShortExtension()
{
new Qyy_G_en_File('read.me');
}

public function testGetSuffixWhenShort()
{
$Qyy = $this->_createQyyFile('read.me');
$this->assertEquals('md', $Qyy->GetSuffix());
}

Кроме того, я хотел бы добавить, что некоторые очень известные программисты подчеркивают правило одно утверждение за тест блока. Как таковой, подумать об этом.

Наконец, я бы порекомендовал быть немного более описательным, чем object0, имя_файла1 и т. д. Попробуйте дать больше значение переменных. Это поможет вам безмерно в 6 месяцев, когда вы посмотрите на ваш код и сидеть там интересно, какова цель этого или что было.

2
ответ дан 7 октября 2011 в 09:10 Источник Поделиться