TDD кто сможет поучить?

AmdY

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

craz

Нестандартное звание
Вынос мозга...

Скачал, поставил mongoDB

Хахаха прикол)

Короче если подключить php_mongo

Создать просто файл class Mongo(){} попросить нетбинс сгенерить тест)

получим вот это)
http://pastebin.com/ruBak5RS

Так всегда бывает?
 

craz

Нестандартное звание
Короче в конце концов первые шаги TDD продумывается тестируемый класс, его свойства и методы.
Методы продумываются с точки зрения входящие переменные, возвращаемое значение.
На основе этого строиться каркас класса и создается тест? Правильно все понял?
Не неправильно:
1.Добавление теста
2.Запуск всех тестов: убедиться, что новые тесты не проходят
3.Написать код
4.Запуск всех тестов: убедиться, что все тесты проходят
5.Рефакторинг
6.Повторить цикл

То есть каркас класса не строиться, только в голове. Получается не удобно, так как в нетбинсе есть возможность создавать тесты по ассертам у функций... соответственно для TDD там нет инструмента) то есть создавать класс по тестам)

Так, но если делать вот так, то создавай простой
PHP:
public function testSetDb() {
        $this->object->setDb();
    }
Тесты вообще никакие не запускаются, просто вываливается ошибка php как быть в таком случае? Тест должен не проходить, а он просто не может даже выполниться из-за ошибки... Как быть моки? Или екзепшены? Или че как?)



P.s. почистите тему плиз.
 

AmdY

Пью пиво
Команда форума
craz
собственно это нефишка нетбинса, это скелетон http://www.phpunit.de/manual/current/en/skeleton-generator.html если в phpstrom добавить в настройки путь к скелетону, то появится нужный пункт с меню.
советую начать с настройки окружения для тестов, я обычно подключаю автолод https://github.com/AmdY/SimplePhpFramework/tree/master/test
Соответственно не забудь ide указать путь к phpunit.xml
 

craz

Нестандартное звание
Ура разобрался, всем спасибо. Можно закрывать тему
 

isqad

isqad88
Вставлю свои кять попеек.
Есть книга по TDD, ссылка, где все прекрасно описано, как и когда тестировать (примеры на Java и Python, но в PHP есть такой же PHPUnit).
Лично мое мнение Unit тестирование подходит для тестирования классов, методов, условий и циклов.
Для взаимодействия объектов, модулей и т.п. применяется функциональное тестирование, которое также можно осуществить с помощью PHPUnit, но удобнее было бы это делать с помощью технологии BDD (тестирование поведения), где пишешь обычными предложениями (можно даже на русском языке) фичи, а потом реализуешь эти фичи через класс. Подробнее смотрите на Behat, cucumber (он не только для ruby).

Сам я только учусь практики TDD и BDD.

Попробем разобраться с вашим примером.

Вам необходимо реализовать метод isFileCss($file).
По TDD пишем тест до реализации этого метода.
public function testIsFIleCss()
{
$file = "style.css";
$this->assetTrue(isFileCss($file));
}
Основной принцип TDD - красный - зеленый - рефакторинг.
Красный - при запуске теста (у нас нет еще кода, к-рый тестируем), видим красную полоску.
Пишем быстро простую реализацию этого метода, например так:
function isFileClass($file)
{
return true;
}
Запускаем тест - видим зеленую полоску - успех!

Делаем рефакторинг:
function isFileCss($file)
{
$fileinfo = pathinfo($file);

return $fileinfo['extension'] === 'css';
}
Запускаем тест - зеленая полоска, ура!
И так далее.
Может конечно, мой пример и не идеален, но, надеюсь, суть вы поняли :)
Успехов вам в начинании.
 
  • Like
Реакции: craz

AmdY

Пью пиво
Команда форума
Нельзя сразу писать положительные тесты, иначе получим 100% покрытие зелёными тестами, но кучу фейлов в реальном проекте, особенно при регрессиях.
PHP:
public function testIsFIleCss()
{
    $file = "style.js";
    $this->assetFalse(isFileCss($file));
    $file = "style.css";
    $this->assetTrue(isFileCss($file));
}
 

craz

Нестандартное звание
У меня подошел следующий цикл попыток разобраться с TDD))

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

Но если в этом классе мы хотим производить еще и некие манипуляции с этим файлом то там уже будет больше кода, и вот его уже есть смысл тестировать?
 

Ragazzo

TDD interested
craz
смысл TDD, а именно unit-testing не в тестировании того что уже есть, а в написании нового кода(!) через тестирование(!).
 

fixxxer

К.О.
Партнер клуба
Ragazzo
Да, но это не значит, что нельзя перейти на TDD методом покрытия существующего кода тестами.
Новый код - да, конечно.
 

Ragazzo

TDD interested
fixxxer
не, ну я так и перешел :D но потом забил нах на покрытие уже существующего кода всего, ибо сразу чувствуется где код писался через TDD и где нет. и иногда приходилось "изголяться" с моками и прочим, на уже написанном коде.
 

craz

Нестандартное звание
craz
смысл TDD, а именно unit-testing не в тестировании того что уже есть, а в написании нового кода(!) через тестирование(!).
а я про че?
Я сначала начал писать тест на открытие фтп... Ну так то да я ламо в этом, ничего путного то я не написал, но думаю ладно щас посмотрим сколько сам функция по всем правилам будет занимать.

Получилось чето типа

PHP:
function setConnection(){
        if ( !($this->_connection = ftp_connect($this->getServerAddress())) ){            
            throw new \Exception("Dont create connection",1);
        }
        return $this;
    }
Ну и что тут тестировать то??? Я реально не понимаю(
 

craz

Нестандартное звание
не придирайся) щас уберу.. Я просто перетасовывал методы..(причем все для того, чтобы понять, что можно было бы в таком классе потестировать) В один момент это была другая функция) и называлась даже по другому...
 

fixxxer

К.О.
Партнер клуба
а я про че?
Я сначала начал писать тест на открытие фтп... Ну так то да я ламо в этом, ничего путного то я не написал, но думаю ладно щас посмотрим сколько сам функция по всем правилам будет занимать.

Получилось чето типа

PHP:
function setConnection(){
        if ( !($this->_connection = ftp_connect($this->getServerAddress())) ){            
            throw new \Exception("Dont create connection",1);
        }
        return $this;
    }
1)
Это не setConnection. setConnection было бы так
PHP:
function setConnection($connection) {
    $this->connection = $connection;
}
Это connect().

2)
То, что написано, сразу делает код нетестируемым. Надо иметь возможность скормить соединение снаружи:

PHP:
protected function getConnection() {
    if (null === $this->connection) {
        $this->connect();
    }
    return $this->connection;
}

protected function connect() {
     $this->connection = ftp_connect($this->address);
}

public function setConnection($resource) {
      $this->connection = $resource;
}
3)
Если это не класс FtpClient, а что-то выше уровнем, то надо ввести class FtpClient, работающий с ресурсом, а в остальных местах работать с instanceof FtpClient.
 
  • Like
Реакции: craz

craz

Нестандартное звание
PHP:
<?php


namespace Craz\Ftp;

class FtpWorker {

    protected $_connection;
    protected $_serverAddress;

    function __construct($serverAddress) {
        $this->_serverAddress = $serverAddress;
        $this->connect($serverAddress)->ftpLogin("app", "app");
    }

    function getServerAddress() {
        return $this->_serverAddress;
    }

    function ftpLogin($username, $password) {
        if (!ftp_login($this->_connection, $username, $password)) {
            throw new \Exception("FTP credentials are incorrect", 3);
        }
    }

    function connect() {
        if (!($this->_connection = ftp_connect($this->getServerAddress()))) {
            throw new \Exception("Connection has not been established", 1);
        }
        return $this;
    }

    function getConnection() {
        if (null === $this->_connection) {
            $this->connect();
        }        
        return $this->_connection;
    }

   //интересная функция она вообще в реале как может пригодиться не додумаюсь...
    function setConnection($resource) {
        $this->_connection = $resource;
    }

    function __destruct() {
        if ($this->_connection) {
            ftp_close($this->_connection);
        } else {
            throw new \Exception("Connection has not been established. Delete something.", 2);
        }
    }

}
На что в таком классе надо было сначала написать тест?
 

fixxxer

К.О.
Партнер клуба
А зачем нужен такой класс? Предполагается, что снаружи будет FtpWorker->getConnection и работа ftp-функциями? Нафиг не нужен такой класс =)

Банальный враппер тестировать смысла особо нет. Все равно не протестируешь. А вот когда здесь будут функции put(), get(), list() и подобные - то вот там, где ты его будешь использовать, сделаешь мок а этот воркер.
 
  • Like
Реакции: WMix
Сверху