Как сделать программу для тестирования

Хочу создать программу которая будет проводить тестирования и при этом каждый мог сам составить тест. Но как это реализовать не знаю. Какие способы есть. Графику сделаю на фреймворке PyQt5. Как я это вижу. Для самостоятельного составление тестов можно в файл .txt делать записи следующим образом:

[vopros]Вопрос 1[vopros] [v1]Вариант ответа 1[v2]

и тд. После чего основная программа как то читает данную запись и создает отдельное окно с таким тестом и вариантами ответов.

Отслеживать
Андрей Александров
задан 16 ноя 2021 в 19:30
Андрей Александров Андрей Александров
570 1 1 серебряный знак 11 11 бронзовых знаков
16 ноя 2021 в 20:34

17 ноя 2021 в 12:45

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Можно использовать xml, а можно, например, json, что может быть удобнее, но это дело вкуса

Создаете файл json, допустим вот такого вида:

< «q»: [ // Опросник «q» < // Первый вопрос с «id»: 0, «text»: «» // Текст вопроса «vars»: [ // Варианты ответов < // Вариант 1 с «id»: 1 «txt»: «. » // Текст ответа >, < // Вариант 2 «id»: 2 «txt»: «. » >, . ], «ans»: [2, 3] // id правильных ответов // (id — потому что вы можете изменять последовательность // вариантов ответов и, при этом, не придется править сам массив ответов) >, < // Второй вопрос и так далее . >] >

Здесь, если ans имеет длину 1 , то правильный вариант, соответственно, один, а если длина больше 1, то (драматическая пауза) и правильных ответов пользователь может выбрать несколько.

C# Программа для тестирования

Весь код за вас я, естественно, писать не буду, но он не сложный и выглядит приблизительно так (крупными мазками):

import json class QuizWindow(. ): # Окно опросника def __init__(self): # Сигнал answer «выбрасывается» из виджета каждый раз когда # пользователь выделяет (или отменяет) вариант ответа (ответов) self.widgetQPage.answer.connect(self.answer) # Загрузка опросника (вызывается, например, при выборе соответствующего пункта меню) def load(self): # загружаем файл и берем из него данные из поля «q» (вопросы типа «q») with open(«quizzes.json», «r») as read_file: self.q_data = json.load(read_file)[«q»] self.qIdx = 0 # Устанавливаем индекс текущего вопроса в 0 # Пользователь выбрал и нажал кнопку «следующий вопрос», или «начать» def nextQ(self): if self.qIdx < len(self.q_data): # Инициализируем виджет вопроса # первый аргумент — индекс вопроса # второй — сам вопрос self.widgetQPage.setQuizzes(self.qIdx, self.q_data[self.qIdx]) self.qIdx += 1 # Смещаем индекс else: # Вопросы закончились — показываем результат # Слот для получения ответов пользователя def answer(self, idx, ans_ids): # Сохраняем ответ пользователя (например в ассоциативный массив) # в котором ключ — это номер вопроса (idx), а значение это массив id ответов (ans_ids)

Здесь widgetQPage имя объекта виджета в котором отображаются вопросы и из которого собираются ответы пользователя (например, через сигнал), может состоять из текстового поля самого вопроса и таблицы/списка для выбора варианта ответов/ответа

Читайте также:
Бэст бухгалтерская программа описание

Создание тестов для проведения экзаменов

Источник: ru.stackoverflow.com

Делаем простые автотесты на Python

Продолжаем погружаться в работу тестировщика, он же — QA, quality assurance engineer. Его задача — проверить код на наличие ошибок и работу программы в разных условиях.

Создание APP для самотестирования (Python)

На базе GUI библиотеки Tkinter

Недавно от знакомых прилетела задачка написать программу для самотестирования. Порылся в инете, думал в лёгкую найду наработки, но ничего кроме платных и бесплатных конструкторов тестов не нашёл (может плохо искал, кто знает…). Мне показалось, что устанавливать какие-то инородные проги, а потом ещё туда все вопросы ручками забивать — совсем некрасиво. Так родилось приложение для самотестирования, написанное на Python с помощью GUI библиотеки Tkinter.

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

Я обозначил следующие требования:

  • Каждый вопрос должен начинаться с числа и точки (метка для идентификации вопросов)
  • Каждый ответ может начинаться с любого символа, но затем обязательно должна идти скобка (метка для идентификации ответов)
  • Правильные варианты ответа должны быть отмечены знаком «+» (метка для идентификации правильных ответов)
  • Вариантов ответа должно быть ровно 5:
    !Если ответов меньше ПЯТИ, то их НУЖНО добить пустыми, например, если их три то добавить 4) и 5)
    !Если вариантов ответа более ПЯТИ, то приложение не будет корректно работать

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

Пример содержимого txt файла:

Пример файла с тестом

Напомню, что построение программы с помощью Tkinter основывается на СОП (событийно-ориентированном программировании). При таком подходе в коде явным образом выделяется главный цикл приложения, тело которого состоит из двух частей: выборки события и обработки события.

В моём случае главный цикл представляет из себя class Block, который вызывается в mainloop():

######################### # Блок обработки событий. ######################### class Block: # Инициализация объектов def __init__(self, master): # счетчик количества вопросов self.qc = 0 # счетчик количества правильных ответов self.true_points = 0 # *Здесь отображено лишь начало Block
################# # Основной цыкл. ################# window = tk.Tk() window.title(‘Конструктор тестов (VladislavSoren)’) window.resizable(width=False, height=False) window.geometry(‘720×480+400+100’) window[‘bg’] = ‘grey’ first_block = Block(window) window.mainloop()

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

Для большего понимания происходящего пробежимся по алгоритму работы программы, а потом рассмотрим каждый этап в отдельности:

1. Пользователь указывает путь к txt файлу с тестом.

Окно выбора файла

2. Производится парсинг содержимого теста, т.е. формируются список вопросов и список ответов.

3. Пользователь выбирает режим работы (Рандомный порядок вопросов vs обычный порядок).

Окно выбора режима

4. Генерируется список с порядком вопросов.

Читайте также:
Программа тех как набирать формулы

5. «Правильные ответы» пользователь отмечает в чекбоксах.

Пользователь отметил ответы

6. Затем пользователь нажимает кнопку «Ответить». После данного события система переходит в состояние проверки, где:

Пользователь нажал кнопку

  • Истинно-правильные ответы подсвечиваются зелёным
  • Изменяется статус индикатора. Если ошибок НЕТ, то индикатор примет значение «Всё верно», иначе «Есть ошибки»
  • Если «Всё верно», то увеличивается счётчик верных ответов на единицу

7. После того, как пользователь проанализировал свой ответ, он нажимает кнопку «Следующий». После данного события система переходит в состояние смены вопроса, где:

Пользователь нажал кнопку

  • Счётчик вопросов увеличивается на единицу
  • Меняется вопрос и ответы
  • Статус индикатора изменяется на исходный «Выберите ответы:»

8. Когда пользователь ответил на последний вопрос и нажал «Следующий», то высвечивается кол-во правильных ответов за весь тест.

 Пользователь ответил на последний вопрос и нажал кнопку

А теперь немного поподробнее:

1. Пользователь указывает путь к txt файлу с тестом.

################################ # Загрузка теста и его парсинг ################################ window = tk.Tk() # Пользователь указывает путь к txt файлу text_path = filedialog.askopenfilename(title=’Выберите тест’) window.destroy()

2. Производится парсинг содержимого теста, т.е. формируются список вопросов, список ответов и вектор меток.

# разделяем файл на строки по пробелам Text = Text.split(sep=’n’) # отделяем вопросы pattern = r’^d.’ # строка начинается с 1 или 3 цыфр, а затем идёт точка (ограничение на 999 вопросов. ) Text_q = [i for i in Text if len(re.findall(pattern, i)) != 0] print(‘Всего вопросов:’, len(Text_q)) # отделяем ответы pattern = r’^.)’ # строка начинается с одного любого символа, а затем идёт скобка Text_a = [i for i in Text if len(re.findall(pattern, i)) != 0] print(‘Всего ответов:’, len(Text_a))

Далее проходимся по ответам и создаём отдельный вектор с метками правильных ответов формата [1 0 0 0 1 0…], как раз для этого и были нужны «+» при разметке файла.

После данного шага получаем список вопросов Test_q, список ответов БЕЗ меток Test_a и вектор меток flags.

3. Пользователь выбирает режим работы (Рандомный порядок вопросов vs обычный порядок).

################################################################ # Выбор режима (Рандомный порядок вопросов vs обычный порядок). ################################################################ window = tk.Tk() window.title(‘Конструктор тестов (VladislavSoren)’) window.resizable(width=False, height=False) window.geometry(‘240×60+600+300’) window[‘bg’] = ‘white’ # функция закрытия окна при выборе рандомного режима def accept(): window.destroy() RandomState = tk.IntVar() # в данную переменную записывается состояние box (1 или 0) box = Checkbutton(window, text=’Включить случайный порядок?’, variable=RandomState, font=(‘Arial Bold’, 10), relief=’solid’, bd=’1′ ) box[‘command’]=accept box.place(x=12, y=20) window.mainloop()

Здесь главным действующим лицом выступает CheckButton (Чекбокс). Если пользователь ставит в боксе галочку, то переменная RandomState примет значение 1, иначе будет равна 0.

Как только пользователь поставил галку – окно закрывается, а RandomState=1. Если же нам НЕ нужен рандомный режим, то просто можно закрыть всплывающее окно.

4. Генерируется список с порядком вопросов.

####################################### # Получение списка с порядком вопросов. ####################################### Text_q_dict = <> for i, q in enumerate(Text_q): Text_q_dict[i] = q np1 = np.arange(len(Text_q)) order_list = np1.tolist() # Если выбран рандомный режим, то перемешиваем порядок вопросов if RandomState.get(): random.shuffle(order_list)

При выборе рандомного режима order_list будет вида [2 0 3 1 5 4].

5. «Правильные ответы» пользователь отмечает в чекбоксах.

Тут комментарии излишни.

6. Затем пользователь нажимает кнопку «Ответить». Система переходит в состояние проверки.

Читайте также:
Функции процессора обработка данных по заданной программе

Кратко опишу структуру class Block, который вызывается в главном цикле mainloop().

# Инициализация объектов def __init__(self, master): # счетчик количества вопросов self.qc = 0 # счетчик количества правильных ответов self.true_points = 0 # Инициализация вопроса и ответов self.quest = scrolledtext.ScrolledText(window, width=75,height=5) index = order_list[self.qc] # индекс вопроса определяем по order_list self.quest.insert(tk.INSERT, Text_q[index])

Метод __inite__ выполняется единожды при создании объекта класса, т.е. в нём происходит инициализация всех объектов, создаются виджеты и все необходимые привязки событий.

Вот основные привязки:

# Инициализация лэйблов и кнопок self.mark = tk.Label(window, text=’Выберите ответы: ‘, font=(‘Arial Bold’, 12), fg=’Green’, bg=’white’) self.ButGiveAns = Button(text=’Ответить’, font=(‘Arial Bold’, 12)) # кнопка перехода в состояние «ПРОВЕРКА» self.ButGiveAns[‘command’] = self.show_res self.ButNext = Button(text=’Следующий’, font=(‘Arial Bold’, 12)) # кнопка перехода в состояние «СМЕНА ВОПРОСА» self.ButNext[‘command’] = self.next_q

При нажатии кнопки «Ответить» вызовется метод show_res:

# Функция обработки события «ПРОВЕРКА» (нажатие кнопки «Ответить») def show_res(self): # определяем текущий индекс вопроса index = order_list[self.qc] # создаем вектор таргетов и ответов targets = flags[5*index : 5*index + 5] answers = np.zeros(5) answers[0] = self.check1.get() # записываем состояние box1 (0 или 1) в нулевой бит вектора answers answers[1] = self.check2.get() answers[2] = self.check3.get() answers[3] = self.check4.get() answers[4] = self.check5.get() # подсвечиваем истинно верные ответы зелёным цветом (задний фон чекбоксов) for i, box in enumerate([self.box1, self.box2, self.box3, self.box4, self.box5]): if targets[i] == 1: box[‘bg’] = ‘green’ # проверка ответа пользователя (сравнение вектора ответа с вектором таргета) if (targets == answers).sum() == 5: self.mark[‘text’] = ‘Всё верно’ # меняем текст метки на статус «Всё верно» self.true_points += 1 # исли всё верно, то накидываем очко else: self.mark[‘text’] = ‘Есть ошибки’

Главное на что стоит обратить внимание — за индекс мы берём значение из списка order_list. Например, ели мы на втором вопросе (self.qc=1), а order_list = [2 0 3 1 5 4], то индекс будет равен 0.

При нажатии кнопки «Следующий» вызовется метод next_q. О нём в следующем пункте.

7. Пользователь нажимает кнопку «Следующий». Система переходит в состояние смены вопроса и вызывается метод next_q.

Первый важный момент:

# инкрементируем счётчик вопросов self.qc += 1

Затем удаляем подсветку боксов и обновляем поля вопросов и ответов:

# определяем текущий индекс вопроса index = order_list[self.qc] # удаляем подсветку чекбоксов for i, box in enumerate([self.box1, self.box2, self.box3, self.box4, self.box5]): box[‘bg’] = ‘white’ box.deselect() # смена вопроса self.quest.delete(‘1.0’, ‘end’) # очищаем всё поле с индекса «1» до последнего «end» self.quest.insert(tk.INSERT, Text_q[index]) # выводим следующий вопрос

И не забываем про index!

8. Пользователь ответил на последний вопрос и нажал «Следующий» — высвечивается кол-во правильных ответов за весь тест.

# когда ответили на все вопросы -> подводим итоги if self.qc >= len(Text_q): self.FinalScore = tk.Label(window, text=f’Всего правильных ответов: ‘, font=(‘Arial Bold’, 15), fg=’white’, bg=’grey’) self.FinalScore.place(x=360, y=210)

С логикой работы разобрались)

Подытожим:

  • Были обозначенытребованияк структуре файлов, для их корректной обработки приложением
  • Рассмотреныпринципысобытийно-ориентированного программирования
  • Написан GUI на базе библиотекиTkinter
  • Описаналогикаработы приложения

Всем успехов в написании собственных интересных и полезных APP. Делитесь ими, и кто-то обязательно их заценит 😉

Источник: habr.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru