Система тестирования. Часть 6
Ранее, в цикле статей, посвященных написанию системы тестирования, была разработана программа составления теста. Сейчас мы начнем создание самого теста. Для начала определим основные требования к программе:
- Вопросы из файла достаются в случайном порядке
- Тестируемый может перескакивать через вопросы и возвращаться назад
- Правильных ответов может быть несколько
- Варианты ответа к вопросу также выстраиваются случайно
- Имя файла можно передать как параметр командной строки, и программа должна его открыть
- Возможность начать тестирование сначала без перезапуска программы
Алгоритм проверки
После того, как с требованиями разобрались можно перейти к одной из самых важных частей любого теста – проверки. Поскольку у вопроса может быть несколько вариантов ответа, то алгоритм проверки будет несколько нетривиальным.
Смысл его в том, что получается, как бы, что неправильный ответ «бьет» правильный. То есть, если, к примеру, тестируемый выбрал, один верный вариант ответа и один неверный, то вопрос не засчитывается. Если же, он выбрал лишь один верный ответ, к примеру, из двух, то вопрос засчитывается наполовину.
Для того, что бы лучше понять, давайте рассмотрим пример. Пусть есть вопрос с шестью вариантами ответа, и три варианта правильные. Рассмотрим первый вариант: тестируемый отметил все правильные ответы – в таком случае за вопрос он получит 100%. Другой вариант: отметил только два варианта ответа из трех. Тогда получается, что вопрос верен лишь на 66%. Если же выбрать, к примеру, два правильных ответа и один неправильный, то 33%.
Подобный алгоритм с процентами является все же более справедливым, нежели просто «верно» или «неверно».
Расширенная работа с данными
Прежде чем приступить к непосредственно разработке программы-теста, нужно сначала расширить классы, созданные нами во второй части цикла статей (ссылка). То есть классы, описывающие данные из xml файла.
Самым очевидным способом расширения уже существующего класса, является наследование. Его и будем использовать.
Добавим в папку lib еще один unit – StDataTest. Начнем с класса варианта ответа: TStAnswer. Единственное, что нам нужно добавить этому классу – это поле Selected, определяющее, выбран ли вариант ответа или нет.
Класс наследник назовем TStAnswerTest.
- unit StDataTest;
- interface
- uses
- SysUtils, Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs,
- xmldom, XMLIntf, msxmldom, XMLDoc, StdCtrls, Contnrs, StData;
- type
- TStAnswerTest = class(TStAnswer)
- public
- Selected: boolean;
- constructor Create;
- end;
- implementation
- constructor TStAnswerTest.Create;
- begin
- inherited Create;
- Selected := false;
- end;
Теперь нам нужно расширить класс вопроса: TStQuestion. Ему нужно лишь добавить метод Check, который будет проверять выбранные варианты ответа согласно алгоритму, описанному выше.
- TStQuestionTest = class(TStQuestion)
- public
- function Check: Integer;
- end;
- ...
- function TStQuestionTest.Check: Integer;
- var
- i: integer;
- Right: integer; // Количество верных ответов
- // За вычетом неправильных
- AllRight: integer; // Количество верных ответов в вопросе
- tmpAnswer: TStAnswerTest;
- begin
- Right := 0;
- AllRight := 0;
- // Цикл по всем варинатам ответа
- for i := 0 to StAnswerList.Count - 1 do
- begin
- tmpAnswer = TStAnswerTest( StAnswerList.Items[i] );
- // Если текущий вариант ответа правильный
- // Увеличиваем AllRight
- if tmpAnswer.Right then
- Inc( AllRight );
- // Если варинт ответа выбран и он верный
- if ( tmpAnswer.Right =
- tmpAnswer.Selected ) and
- ( tmpAnswer.Right ) then
- Inc( Right ) // Увеличиваем Right
- else if ( tmpAnswer.Selected ) and
- ( not tmpAnswer.Right ) then
- Dec( Right ); // Если же выбран неверный варинт ответа
- // То уменьшаем
- end;
- if Right < 0 then // Если неправильных ответов больше
- Result := 0 // То сбрасываем в ноль
- else // Считаем общий процент
- Result := Round ( ( Right / AllRight ) * 100 );
- end;
Представление варианта ответа
Теперь перейдем к представлению варианта ответа непосредственно в программе. Несмотря на то, что пока никакой программы теста еще даже и нет, с этим нужно разобраться. Создадим в папке Test юнит StAnswerBlock. В нем и будет блок представления варианта ответа.
Возможным вариантом является следующий:
Не отмеченный: 
Отмеченный тестируемым: 
За представление варианта ответа будет отвечать класс TStAnswerBlock, наследованный от TPanel. Рассмотрим картинку блока, так сказать, в разрезе:
- TextLabel– метка, куда выводится текст ответа
- CImage – изображение, видимое, если вариант ответа выбран.
Перечисленные выше компоненты сделаем скрытыми полями класса. Кроме того, добавим к этому классу следующие члены:
- Поле Answer: TStAnswer. Сам вариант ответа
- Свойство Selected: boolean. Доступное для чтения и записи свойство, определяющее отмечен ли тестируемым вариант ответа.
- Свойство AText: string. Текст варианта ответа.
В итоге, объявление класса выглядит так:
- TStAnswerBlock = class(TPanel)
- private
- FSelected: boolean;
- TextLabel: TLabel;
- CImage: TImage;
- function GetAText: string;
- procedure SetAText(const Value: string);
- procedure SetSelected(const Value: boolean);
- public
- Answer: TStAnswer;
- constructor Create(setAnswer: TStAnswer; AOwner: TComponent; setPicture:
- TPicture);
- destructor Destroy; override;
- procedure Click(Sender: TObject);
- property AText: string read GetAText write SetAText;
- property Selected: boolean read FSelected write SetSelected;
- end;
Рассмотрим методы этого класса.
Конструктор
Конструктор принимает три параметра: AOwner, setAnswer – вариант ответа, который будет привязан к этому блоку и setPicture – картинка для поля CImage.
- constructor TStAnswerBlock.Create(setAnswer: TStAnswer; AOwner: TComponent;
- setPicture: TPicture);
- begin
- inherited Create( AOwner );
- Parent := ( TWinControl (AOwner));
- Width := 150;
- Height := 24;
- Color := clWhite;
- ParentBackground := false;
- BevelOuter := bvNone;
- Ctl3D := false;
- BorderStyle := bsSingle;
- ShowCaption := false;
- OnClick := Click;
- CImage := TImage.Create( self );
- CImage.Parent := self;
- CImage.Width := 16;
- CImage.Height := 16;
- CImage.Left := 4;
- CImage.Top := 3;
- CImage.Picture := setPicture;
- CImage.OnClick := Click;
- TextLabel := TLabel.Create( self );
- TextLabel.Parent := self;
- TextLabel.Top := 4;
- TextLabel.OnClick := Click;
- Answer := setAnswer;
- AText := setAnswer.Text;
- Selected := TStAnswerTest( Answer ).Selected;
- end;
Клик по блоку
Метод Click. Обработчик события OnClick по блоку. Задается свойство Selected. То есть, если вариант ответа выбран, то снимаем выбор, или наоборот, если не выбран, то делаем выбранным.
- procedure TStAnswerBlock.Click(Sender: TObject);
- begin
- Selected := not Selected;
- end;
Метод SetSelected
Метод при записи в свойство Selected. В зависимости от значения либо показывает либо убирает картинку.
- procedure TStAnswerBlock.SetSelected(const Value: boolean);
- begin
- CImage.Visible := Value;
- ( TStAnswerTest (Answer) ).Selected := Value;
- if Value then
- begin
- TextLabel.Left := 25;
- Width := TextLabel.Width + 33;
- end
- else
- begin
- TextLabel.Left := 5;
- Width := TextLabel.Width + 12;
- end;
- FSelected := Value;
- end;
Методы SetAText и GetAText
Методы для чтения и записи в свойство AText. Значения записывается и получается из свойства Caption метки TextLabel.
- function TStAnswerBlock.GetAText: string;
- begin
- Result := TextLabel.Caption;
- end;
- procedure TStAnswerBlock.SetAText(const Value: string);
- begin
- TextLabel.Caption := Value;
- end;
На это подготовительная часть к разработке программы-теста завершена. Далее мы перейдем непосредственно к созданию самой программы.
delphi, тест

Комментарии (0)
Добавить комментарий