CSC/ECE 517 Spring 2016 E1621 Refactor and Test the Quizzing Feature

From Expertiza_Wiki
Jump to navigation Jump to search

Introduction to Expertiza

Expertiza<ref>https://github.com/expertiza/expertiza</ref> is a project developed using Ruby on Rails<ref>http://guides.rubyonrails.org/getting_started.html</ref>. It provides features like peer review, team assignments and submission of projects. This can be achieved by submitting code base, URL of hosted code on remote server and Wiki submissions. It is an open source application and the code can be cloned from GitHub. This application provides an efficient way to manage assignments, grades and reviews.

Problem Statement

The Expertiza quiz feature is in need of refactoring. Currently, quizzes are checked by questionnaires_controller.valid_quiz. This method is rather long, involved, and does not take advantage of object-oriented practices. It combs through the parameters hash received from a request and manually checks all quiz fields, all question fields, all question choice fields, and verifies that each question has a correct choice.

We will refactor the method to construct a quiz questionniare and then call valid? to recursively validate the object tree using ActiveRecord validations. This is an improvement over the current code which checks all questions manually. The purpose of refactoring in this manner is to enhance readability, DRYness, and maintainability of Expertiza code.

In addition to this refactoring we will implement integration testing on the quiz feature to verify that the expected behavior is present for all use cases.

A full description of the assignment may be found here

Program flow of this quizzing feature can be found here

Classes involved

  • questionnaires_controller.rb
  • quiz_quesetionnaire.rb
  • quiz_question.rb
  • quiz_question_choice.rb
  • spec/features/quiz_spec.rb

Use Case and Scenarios

The Quiz Use Case allows for instructors to create and manage assignments where students may write quizzes for reviewers on materials they have submitted. See the following scenarios for a complete description of how the feature is expected to work.

Instructors are able to create and manage an assignment's quiz feature

An instructor chooses to create an assignment that has a quiz [S1]. While editing the assignment they may choose the number of quiz questions [S2] and set which phases students are allowed to take the quizzes [S3].

  • [S1] - When creating the assignment there is a checkbox labeled "has quiz." Checking this box creates an assignment that includes a quiz.
  • [S2] - When an assignment has a quiz there is an input field that accepts the number of questions that will be on each quiz. Setting this number appropriately changes the number of quiz questions.
  • [S3] - Students may not take quizzes on a phase that does not allow them to do so. When on a stage that does allow for quizzes, they may take quizzes on work that they have reviewed.

Instructors can view quiz questions and scores from the tree view

After an assignment has been created the instructor may choose to view student quizzes from the tree view [S1]. While on the quiz view page they see student quizzes [S2] and student responses [S3].

  • [S1] - The instructor may navigate to the list of assignments. Assignments with quizzes enabled will provide a link for the instructor to follow and view student quizzes.
  • [S2] - The instructor shall be presented with the quiz title, questions, and answer choices. The correct answer choices will be in bold.
  • [S3] - The score for each student who has taken the quiz shall be listed along with the average quiz score.

Students can create and edit quizzes

A student navigates to the assignment work page and chooses to create a new quiz [S1] or edit an existing one [S2]. By doing so they are able to choose a quiz title and quiz questions [S3]. Invalid input results in an error message prompting the student to fix the issue [E1].

  • [S1] - A student may only create a quiz if they have not yet done so.
  • [S2] - A student may only edit a quiz if they have previously created one.
  • [S3] - The quiz has the number of quiz questions defined by the instructor in the assignment.
  • [E1] - Possible errors include:
    • The quiz has no name.
    • One or more questions is missing text.
    • One or more choices is missing text.
    • A question is missing a correct answer choice.

Students can take quizzes on assignments they have reviewed

A student decides to take a quiz [S1] on another team's assignment that they have previously reviewed. They select an artifact for review [S2] and fill in their answers. After submitting the quiz they can view their score on the take quizzes page [S3] and see question-by-question scores by clicking view [S4].

  • [S1] - The student may only take a quiz during a stage in which the assignment is configured to allow them to do so.
  • [S2] - Only quizzes from submissions they have reviewed are available.
  • [S3] - The take quizzes page lists the final score for each quiz.
  • [S4] - Choosing to view a quiz will show a student each question along with their answers and the correct answers.

Design and Implementation

Design for the refactoring has been driven by object oriented principles and test-driven-development, and makes use of the existing object hierarchy described in the following UML diagram.

Expertiza Quiz Hierarchy

See the below sections for a part-by-part breakdown of the planned implementation for this project.

Tests

Quiz tests will be added to the file spec/features/quiz_spec.rb and will make use of

  • rspec
  • capybara
  • selenium

Tests will be made which fully cover the expected behavior of each listed scenario in the Use Case.

Refactoring

Each of the following files will be refactored as described.

QuestionnaireController

Refactor the valid_quiz method. It will be renamed to validate_quiz to more properly describe the action that occurs as a result of it being called. The behavior will be changed to construct a new quiz questionnaire with submitted questions wich will be validated using quiz.valid?.

QuizQuestionnaire

The following fields will be validated using ActiveRecord validations.

  • Presence of name

QuizQuestion

The following fields will be validated using ActiveRecord validations

  • Presence of text
  • Presence of type
  • Has a correct answer

QuizQuestionChoice

The following fields will be validated using ActiveRecord validations

  • Presence of text

Test Cases

In order to verify that refactoring has been done correctly and maintains the same external behavior, we will write test cases to the existing implementation. These test cases will be the ground truth of the validation feature. Refactored code will not be considered complete until all of these test cases once again pass.

Post Completion

Testing and refactoring have been completed and a pull request created to merge features back into master.

Refactoring

Refactoring went according to plan. The following model files were edited to use ActiveRecord validations on specific fields

  • question.rb
  • questionnaire.rb
  • quiz_quesetion.rb
  • quiz_question_choice.rb

In addition, tests were added to spec/controllers/questionnaires_controller_spec.rb to test quiz validation. With passing tests, the validate_quiz method in questionnaires_controller was refactored. It now constructs a quiz from params and returns it if it is valid. If the quiz is invalid an error message is returned.

Before Refactoring

def valid_quiz

num_quiz_questions = Assignment.find(params[:aid]).num_quiz_questions
valid = "valid"
(1..num_quiz_questions).each do |i|
if params[:new_question][i.to_s] ==
// One of the questions text is not filled out
valid = "Please make sure all questions have text"
break
elsif !params.has_key?(:question_type) || !params[:question_type].has_key?(i.to_s) || params[:question_type][i.to_s][:type] == nil
// A type isnt selected for a question
valid = "Please select a type for each question"
break
elsif params[:questionnaire][:name]==""
// questionnaire name is not specified
valid = "Please specify quiz name (please do not use your name or id)."
break
else
type = params[:question_type][i.to_s][:type]
if type == 'MultipleChoiceCheckbox' or type == 'MultipleChoiceRadio'
correct_selected = false
(1..4).each do |x|
if params[:new_choices][i.to_s][type][x.to_s][:txt] ==
// Text isnt provided for an option
valid = "Please make sure every question has text for all options"
break
elsif type == 'MultipleChoiceRadio' and not params[:new_choices][i.to_s][type][x.to_s][:iscorrect] == nil
correct_selected = true
elsif type == 'MultipleChoiceCheckbox' and not params[:new_choices][i.to_s][type][x.to_s][:iscorrect] == 0.to_s
correct_selected = true
end
end
if valid == "valid" && !correct_selected
// A correct option isnt selected for a check box or radio question
valid = "Please select a correct answer for all questions"
break
end
elsif type == 'TF' # TF is not disabled. We need to test TF later.
if params[:new_choices][i.to_s]["TF"] == nil
// A correct option isnt selected for a true/false question
valid = "Please select a correct answer for all questions"
break
end
end
end
end
return valid

end

After Refactoring

def validate_quiz

num_quiz_questions = Assignment.find(params[:aid]).num_quiz_questions
questionnaire = quiz_questionnaire num_quiz_questions
if questionnaire.valid?
return questionnaire
end
questionnaire_errors questionnaire

end

Testing

All tests were implemented as part of spec/features/quiz_spec.rb and thoroughly cover the Use Case, scenarios, and sub flows listed above. A factory file, spec/factories/quiz_factory.rb was added to aid testing.

References

<references/>