[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Несколько вопросов вразброс



26.06.2012 12:54, Igor Chumak пишет:
> 25.06.2012 18:03, "Артём Н." пишет:
>> Я "наворачиваю" не для того, чтобы "круто на баш написать" и не из-за проблем с
>> головой, а для того, чтобы попробовать TDD (или хотя бы просто unit тесты) там,
>> где его обычно не используют... На перспективу. Пока что, не особенно хорошо
>> получается. :-)
>>
>>
> Было бы интересно посмотреть.
Да что там интересного? Я только пытаюсь, пока-что. Взял небольшую задачу,
которую требуется выполнить. Конкретно: требуется бэкап-скрипт. Но нужно
сохранять не только иерархию каталогов, но и некоторые служебные данные: LVM,
LUKS заголовки, дамп БД и т.п.. Причём, используя для бэкапа тот же самый
rdiff-backup, который используется для сохранения каталогов.
Каталоги для сохранения - в отдельном списке.
На очереди задачка побольше, поэтому думаю, стоит попробовать на совсем небольшом.
Для этого я сделал:
1. Функцию assert:
###TESTING
assert()
# $1 - message;
# $2 - comannd.
{
   echo "Command: $2"
   eval $2 || { echo "$1" && exit 1; }
   return 0;
}
###/TESTING

2. Теги ###TESTING ###/TESTING.
Не мудрствуя лукаво, реализовав обработку на awk:
#!/bin/sh

fl="$1"
fl=${-:-$fl}

awk '
   BEGIN {
      prf = 0;
   }

   /^#!\/bin\/bash/ {
      print "#!/bin/sh";
      next;
   }

   /###TESTING/ {
      prf = pfm + 1;
      next;
   }

   /###\/TESTING/ {
      if (prf == 0)
      {
         print "Error: unexpected ###\/TESTING" > "/dev/stderr";
         exit 1;
      }
      prf = prf - 1;
      next;
   }

   {
      if (prf == 0) print;
   }

   END {
      if (prf > 0)
      {
         print "Error: unclosed ###TESTING";
         exit 1;
      }
   }
' "$fl"

3. Функцию dbg со товарищи, для вывода сообщений, соответствующих уровню
"разговорчивости":
dbg()
# $1 - verbosity level;
# $2 - message.
{
   [ "$V_LEVEL" -ge "$1" ] && echo "$2" > /dev/stderr
}

err()
# $1 - message.
{
   dbg 1 "$1"
   dbg 0 "Backup failed..." # failed...&& exit 1
   return 1
}

Вложенные функции (в функции сохранения служебной информации каждое действие
оформлено маленькой функцией, вложенной в основную) проверяются модульными
тестами внутри "функции-родителя" (в тегах ###TESTING).
Каждая внешняя функция проверяется в главной функции, заменяющей реальную главную.
(Например, вызывается main, которая переопределяется в тегах ###TESTING, на
вызов тестирующей функции).

В итоге получается какой-то намёк на модульные тесты, плюс на что-то
"интегративное".

Внутри каждой тестирующей функции проверяется правильное поведение и реакция на
ошибку (в случае ошибки, функция должна возвращать свой код отличный от нуля или
$?, если была выполнена команда перед завершением). Ну и "граничные условия",
если имеются.
К примеру:
   assert "backup_kernel_conf error 0" "backup_kernel_conf bla-bla-bla...
\"$PWD/_config\"||true"
   assert "backup_kernel_conf error 1" "backup_kernel_conf \"$LINUX_CONFIG\"
\"$PWD/_config\""

Сделано грязновато, но хоть что-то... К TDD это относится мало. Разве что, я
пытаюсь вначале писать тесты.

Собственно, на этом всё.


Reply to: