Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

X-Program ПО, новости сайта и программирование в Delphi7 #9


Информационный Канал Subscribe.Ru

 

Компания X-Program 

В сегодняшнем выпуске:

Извините за MagDate3!
Как стереть EXE файл во время его исполнения?
Экстремальное программирование
!Бесплатная реклама Вашего сайта в нашей рассылке!

 

 

Если Вам небезразлична дальнейшая судьба наших программ, и вы хотите внести свой личный вклад в развитие проекта, то можете воспользоваться платёжной системой Яндекс.Деньги.
   Оплата Яндекс.Деньгами
Сумма: руб. коп.

 

Извините за MagDate3

 

Привет всем!
Если Вы уже скачивали MagDate3, то могли заметить что программа не работает.
Оказалось программа работает только на моём компе :-)
Оказалось ошибка в коде программы. Но сейчас ошибка уже исправлена.
В данный момент идёт тестирование и доработка программы.
Выход ожидается на конец ОКТЯБРЯ.
Вы можете посетить
наш сайт
www.x-program.narod.ru
сайт программы MagDate
www.magdate.narod.ru
или нашу гостевую книгу
http://xbase.ru/?xprogram

 

Как стереть EXE файл во время его исполнения?

 

Это невозможно. Вы можете стереть его во время следующего запуска Windows, добавив ключ RunOnce:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce
Пример:


     uses
       Registry;

     procedure TForm1.Button1Click(Sender: TObject);
     var
       reg: TRegistry;

     begin
       reg := TRegistry.Create;

       with reg do begin
     RootKey := HKEY_LOCAL_MACHINE;
     LazyWrite := false;
     OpenKey('Software\Microsoft\Windows\CurrentVersion\RunOnce',
             false);
     WriteString('Delete Me!','command.com /c del FILENAME.EXT');
     CloseKey;

    free;
       end;
     end;


Можно еще через bat файл


:Repeat
del "C:\Path\Filename.EXE"
if exist "UNSETUP.EXE" goto Repeat
del "C:\Path\Del.bat"


Или прописать в C:\Windows\wininit.ini следующее, для этого воспользоваться компонентом TIniFile

wininit.ini

[rename]
NUL=filename-to-delete

 

Экстремальное программирование

 

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

Идея этой методики состоит в следующем: представляете, как будет использоваться функция, вызываете её с тестовыми параметрами, сравниваете желаемый и реально полученный результат. Рекомендуется не задумываться над вариантами реализации конкретной функции, только над тем, как она будет использоваться. Эта методика не только повышает качество продукта многократно, но и позволяет обрести чувство уверенности в своей работе.

Попробуем сказанное на примере пользовательского рейтинга статьи. Идея примера возникла, глядя на распечатанную статью с Microsoft-а. Пользователю дана возможность поставить свою оценку статьи, от 1 до 9. Правее отображается гистограмма распределения оценок, их среднее значение и количество голосовавших. Для простоты пропустим запись данных в файл или базу, кому интересно, смогут это сделать самостоятельно, добавив дополнительно пару тестов.

Итак, сначала определимся с интерфейсом класса. Назовём его Vote. Кому не жалко времени, может сделать это в Rose, я обычно предпочитаю карандаш и бумагу, или сразу начисто, в редакторе кода. Настроение, навеянное статьями сайта Microsoft, подталкивает меня сделать пример на C#. Правда лучше C++ пока ещё никто ничего не придумал.

public class Vote
{
 public void Add(int vote)
 {
 }

 public int CalculateRating(int vote)
 {
 }

 public int CalculateAverageRating()
 {
 }

 public int GetRatesCount()
 {
 }
}

Теперь заводим отдельный проект для тестовых случаев, как это делается, я описывал в статье "Внедрение ведомого тестированием метода разработки для языков .Net". Определяем класс VoteTest, для тестовых случаев, и сразу же помозговому атакуем его на предмет возможных тестовых ситуаций.

[TestFixture]
public class VoteTest : Assertion
{
 [Test]
 public void TestHystogram()
 {
  Assert(false);
 }
 [Test]
 public void TestRatesCount()
 {
  Assert(false);
 }
 [Test]
 public void TestAverageRating()
 {
  Assert(false);
 }
}

Да, можно было и не мозговать, а просто добавить слово Test ко всем методам, определённым в Vote. Assert(false) нужно просто чтоб не забыть, что тест ещё не готов, своеобразный "to do list". Начнём с TestRatesCount, т.к. он кажется мне самым простым.

public void TestRatesCount()
{
 Vote vote = new Vote();
 int nVotes = 26;
 for(int i = 0; i < nVotes; i++)
 {
  vote.Add(9);
 }
 AssertEquals(nVotes, vote.GetRatesCount());
}

Компилируем, появились первые ошибки. Исправляем их простым добавлением return 0; где нужно в классе Vote. Теперь всё будто бы успешно компилируется. Запускаем NUnit, кто ещё не установил, может найти последнюю версию на сайте nunit.org. Все тесты светятся красным, что свидетельствует об их работоспособности. Теперь наша задача добавить в класс Vote функциональность, требуемую этим тестом.

Первое, что приходит на ум - это добавить объект ArrayList в наш класс:

protected ArrayList votesList = new ArrayList();

Сразу же добавим к нему property accessor, как этого требуют правила хорошего кода:

public IList VotesList
{
 get
 {
  return this.votesList;
 }
}

Методы Add и GetRatesCount будут содержать всего лишь по одной строке:

public void Add(int vote)
{
 VotesList.Add(vote);
}
public int GetRatesCount()
{
 return VotesList.Count;
}

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

Переходим к следующему тесту, своей простотой меня привлекает тест среднего значения голосов: TestAverageRating.

[Test]
public void TestAverageRating()
{
 Vote vote = new Vote();
 int[] testVotes = {2, 4, 3, 3, 2, 4}; // avg = 3
 foreach(int value in testVotes)
 {
  vote.Add(value);
 }
 AssertEquals(3, vote.CalculateAverageRating());
}

Сразу же просится тест на правильность округления:

[Test]
public void TestAverageRatingRoundingUp()
{
 Vote vote = new Vote();
 int[] testVotes = {2, 3, 3}; // avg = 2.66
 foreach(int value in testVotes)
 {
  vote.Add(value);
 }
 AssertEquals(3, vote.CalculateAverageRating());
}
[Test]
public void TestAverageRatingRoundingDown()
{
 Vote vote = new Vote();
 int[] testVotes = {4, 4, 5}; // avg = 4.33
 foreach(int value in testVotes)
 {
  vote.Add(value);
 }
 AssertEquals(4, vote.CalculateAverageRating());
}

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

Займёмся реализацией метода CalculateAverageRating, легко ощутимая цель: выполнение последних трёх тестов. Пытаемся её достичь, определив метод следующим образом:

public int CalculateAverageRating()
{
 int sum = 0;
 foreach(int value in VotesList)
 {
  sum += value;
 }
 return sum / GetRatesCount();
}

Запускаем тесты, чтобы проверить, действительно ли мы добились желаемой цели. Они нас убеждают в обратном: тест округления к большему не пройден. Но настойчивости нам не занимать, попробуем определить, в чём же проблема. Сразу видно, что целочисленное деление нам не подходит, поэтому преобразуем тип переменной sum к double:

double sum = 0;

Результат не изменился, тест всё ещё не проходит. Тогда придётся явно указать процедуру округления:

public int CalculateAverageRating()
{
 double sum = 0;
 foreach(int value in VotesList)
 {
  sum += value;
 }
 double avg = sum / GetRatesCount();
 return (int)Math.Round(avg);
}

Всё, цель достигнута, тесты выполняются.

Направленность на результат в таких мелочах непременно воспитывает дисциплинированность и целеустремлённость в работе и жизни.

Остались ещё один тест, и ещё одна функциональность: данные для построения гистограммы оценок.

От функции CalculateRating мы ожидаем процентное соотношение той или иной оценки к общему числу голосов. Так и запишем:

[Test]
public void TestHystogram()
{
 Vote vote = new Vote();
 int[] testVotes = {2, 4, 3, 3, 2, 4, 5, 2, 2, 2};
 int[] expectedResults = {0, 50, 20, 20, 10, 0, 0, 0, 0};
 foreach(int value in testVotes)
 {
  vote.Add(value);
 }

 int iValue = 1;
 foreach(int result in expectedResults)
 {
  string message = "For " + iValue;
  AssertEquals(message, result, vote.CalculateRating(iValue));
  iValue++;
 }
}

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

public int CalculateRating(int vote)
{
 double nSpecificVotes = 0;
 foreach(int value in VotesList)
 {
  if(vote == value)
  {
   nSpecificVotes++;
  }
 }
 return (int)nSpecificVotes * 100 / GetRatesCount();
}

На округлении можно не заостряться, тест и так работает. А вот на что следует обратить внимание, так это на то, что в этом методе есть операция деления, знаменатель которой может равняться нулю. Отработаем это в самом начале:

if(GetRatesCount() == 0)
{
 return 0;
}

Если вы заметили, я не сделал ни одного комментария в коде. Всё должно быть и так понятно по названиям переменных и тестовым случаям.

Код примера можно скачать здесь.

Теперь представьте, сколько бы труда и ресурсов ушло на достижение того же уровня качества, если бы мы не использовали модульные тесты. О том, что эти тесты будут жить, пока жив класс Vote, и самостоятельно проверять функциональность, я просто не хочу говорить.

Ну что, кто хочет закрепляющее упражнение? Совсем простое, для ленивых:

Добавить тест, проверяющий сохранение результатов между сессиями.

 

 

Присылайте свои пожелания, вопросы, интересные истории, анекдоты и т.п.

Всё опубликуем в рассылке! 

Имя:
Тема:
Сообщение:
function checkIt() { // функция проверки полей формы //----------- if (document.forms.mailer.Name.value != "") { // функция проверки поля Name } else { alert("\nОбласть \"Имя\" в форме. \n\nПожалуйста, введите свое имя."); // выводит сообщение, если поле Name не заполнено document.forms.mailer.Name.focus(); // возврашает курсор на поле Name return false; } //----------- if (document.forms.mailer.Subject.value != "") { // функция проверки поля Subject } else { alert("\nОбласть \"Тема\" в форме. \n\nПожалуйста, введите тему."); // выводит сообщение, если поле Subject не заполнено document.forms.mailer.Subject.focus(); // возврашает курсор на поле Subject return false; } //----------- if (document.forms.mailer.Message.value != "") { // функция проверки поля Message return true; // ВСЕ ОТЛИЧНО } else { alert("\nОбласть \"Сообщение\" в форме. \n\nПожалуйста, напишите сообщение."); // выводит сообщение, если поле Message не заполнено document.forms.mailer.Message.focus(); // возврашает курсор на поле Message return false; } //----------- } function msg() { // функция отправки document.mailer.action = "mailto:X-Program@mail.ru" mailtoandSubject = (('?Subject=' + document.mailer.Subject.value) + '&Body=' + document.mailer.Message.value); }

http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.prog.program
Отписаться

В избранное