CSC/ECE 517 Spring 2017/oss E1729: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
m (→‎Test Plan: making flow chart bold.)
 
(37 intermediate revisions by 3 users not shown)
Line 1: Line 1:
==Introduction==
==Introduction==


This project was an addendum to the bigger Expertiza project. The Expertiza project is software to create reusable learning objects through peer review. It also supports team projects, and the submission of almost any document type, including URLs and wiki pages.
This project is an addendum to the bigger Expertiza project. The Expertiza project is software to create reusable learning objects through peer review. It also supports team projects, and the submission of almost any document type, including URLs and wiki pages.


The requirement for this OSS project was to ''''Export Scores In Detail''''
The requirement for this OSS project was to ''''Export Scores In Detail''''
Line 10: Line 10:


==Branch on Git==
==Branch on Git==
The branch on which we developed this project on is called ''''exportdetail''''
The branch on which we developed this project on is called [https://github.com/kkushagra/expertiza/tree/exportdetail : ''''exportdetail'''']


==Problem Statement==
==Problem Statement==
Expertiza provides a the ability for an instructor to export scores for an assignment. Whenever a user fill out teammate reviews, peer reviews, feedback reviews, and etc. the scores for each question on those reviews is stored in the database. Currently however Expertiza only exports a csv with aggregated scores which are computed as weighted averages of the scores given in reviews. This is not the most helpful for visualizing the score data by question, individual team/user, reviewer. So it was our assignment to implement the ability to export a more detailed csv that contained all the scores for each question for each review and review type within a specific assignment.
Expertiza provides a the ability for an instructor to export scores for an assignment. Whenever a user fills out teammate reviews, peer reviews, feedback reviews, and etc. the scores for each question on those reviews are stored in the database. Currently however Expertiza only exports a csv with aggregated scores which are computed as weighted averages of the scores given in reviews. This is not the most helpful for visualizing the score data by question, individual team/user, reviewer. So that is why our assignment is to implement the ability to export a more detailed csv that contained all the scores for each question for each review and review type within a specific assignment.


Part of the implementation includes the ability to choose the delimiter for the csv and specify which columns they wanted to include.
After talking with our project contact, Ferry, it was decided that the csv would be organized by round and within each round by response type. Part of the implementation was to also include the ability to choose the delimiter for the csv and specify which columns they wanted to include.


==Design==
==Design==
So the reason we implemented our feature a certain way is because there was already previous code for exporting an aggregate csv so we designed our feature in the same fashion. An export controller already existed so we added a new method in that for exporting details and modeled it based on the already existing export method. Assignment.rb already had the methods for setting columns/fields and getting aggregate export info so we added our implementations corresponding methods in that class as well. For the view, we simply added our code, that linked to the new controller method, in the same view where the other csv feature was implemented. No specific design pattern was used, but our feature was simply modeled after previously existing similar features.


==Implementation==
==Implementation==
Line 32: Line 33:
===Code Snippets===
===Code Snippets===
*export_file_controller_spec.rb
*export_file_controller_spec.rb
This method is called when the 'Export Details' button is clicked and selects the delimiter and generates the csv with selected columns. It then passes the CSV into the assignment models method to populate it.


  def exportdetails
  def exportdetails
Line 56: Line 59:
       end
       end
     end
     end
   
 
     send_data csv_data,
     send_data csv_data,
               type: 'text/csv; charset=iso-8859-1; header=present',
               type: 'text/csv; charset=iso-8859-1; header=present',
Line 64: Line 67:


*app/models/assignment.rb
*app/models/assignment.rb
This method is called to populate it the csv and is where the majority of our implementation lies. It finds all the ResponseMaps associated with this assignment, then finds all the Responses associated with that each ResponseMap. Then for each response it saves the Answer objects associated with it into an array that is stored in a hash that is indexed by round and response type (teammate review/feedback review/etc).
<code>
   def self.export_details(csv, parent_id, detail_options)
   def self.export_details(csv, parent_id, detail_options)
    return csv unless detail_options.value?('true')
   
     @assignment = Assignment.find(parent_id)
     @assignment = Assignment.find(parent_id)
 
     @answers = {} # Contains all answer objects for this assignment
     @answers = {} # Contails all answer objects for this assignment
    # Find all unique response types
 
     @uniq_response_type = ResponseMap.uniq.pluck(:type)
    #Find all unique response types
    # Find all unique round numbers
     @uniq_response_type = ResponseMap.uniq.pluck(:type)
     @uniq_rounds = Response.uniq.pluck(:round)  
    #Find all unique round numbers
    # create the nested hash that holds all the answers organized by round # and response type
     @uniq_rounds = Response.uniq.pluck(:round)
 
    #create the nested hash that holds all the answers organized by round # and response type
     @uniq_rounds.each do |round_num|
     @uniq_rounds.each do |round_num|
       @answers[round_num] = {}
       @answers[round_num] = {}
Line 81: Line 87:
       end
       end
     end
     end
 
     @answers = generate_answer(@answers, @assignment)
    #get all response maps for this assignment
     # Loop through each round and response type and construct a new row to be pushed in CSV
     @responseMapsForAssignment = ResponseMap.find_by_sql(["SELECT * FROM response_maps WHERE reviewed_object_id = #{@assignment.id}"])
   
     #for each map, get the response & answer associated with it
    @responseMapsForAssignment.each do |map|
      @responseForThisMap = Response.find_by_sql(["SELECT * FROM responses WHERE map_id = #{map.id}"])
      #for this response, get the answer associated with it
      @responseForThisMap.each do |res_map|
        @answer = Answer.find_by_sql(["SELECT * FROM answers WHERE response_id = #{res_map.id}"])
       
        @answer.each do |ans|
          @answers[res_map.round][map.type].push(ans)
        end
     
      end
     
    end
 
     @uniq_rounds.each do |round_num|
     @uniq_rounds.each do |round_num|
     
       @uniq_response_type.each do |res_type|
       @uniq_response_type.each do |res_type|
          
         round_type = check_empty_rounds(@answers, round_num, res_type)
        if @answers[round_num][res_type].size > 0
        unless round_type.nil?
          if round_num.nil?
           csv << [round_type, '---', '---', '---', '---', '---', '---', '---']
            round_type = "Round Nill - " + res_type
          else
            round_type = "Round " + round_num.to_s + " - " + res_type.to_s
          end
         
           csv << [round_type, '---', '---', '---', '---', '---', '---']
         end
         end
         @answers[round_num][res_type].each do |answer|
         @answers[round_num][res_type].each do |answer|
           row = []
           csv << csv_row(detail_options, answer)
          tcsv = []
        end
      end
    end
  end
</code>


          @response = Response.find_by_id(answer.response_id)
This method checks nil while populating a csv field headers to only add headers which the user selected from the checkboxes.
          ans = ResponseMap.find_by_id(@response.map_id)


          @reviewee = Team.find_by_id(ans.reviewee_id)
  def self.handle_nil(csv_field)
          if @reviewee.nil?
    return ' ' if csv_field.nil?
            @reviewee = Participant.find_by_id(ans.reviewee_id).user
    csv_field
          end
  end


          reviewer = Participant.find_by_id(ans.reviewer_id).user
This method generates a CSV row by looping through the answers.


            if @reviewee.nil?
  # Generates a single row based on the detail_options selected
              tcsv << ' '
  def self.csv_row(detail_options, answer)
            else
    tcsv = []
              if detail_options['team_id'] == 'true'
    @response = Response.find_by_id(answer.response_id)
                tcsv << @reviewee.id  
    ans = ResponseMap.find_by_id(@response.map_id)
              end
    @reviewee = Team.find_by_id(ans.reviewee_id)
            end
    @reviewee = Participant.find_by_id(ans.reviewee_id).user if @reviewee.nil?
    reviewer = Participant.find_by_id(ans.reviewer_id).user
    tcsv << handle_nil(@reviewee.id) if detail_options['team_id'] == 'true'
    tcsv << handle_nil(@reviewee.name) if detail_options['team_name'] == 'true'
    tcsv << handle_nil(reviewer.name) if detail_options['reviewer'] == 'true'
    tcsv << handle_nil(answer.question.txt) if detail_options['question'] == 'true'
    tcsv << handle_nil(answer.question.id) if detail_options['question_id'] == 'true'
    tcsv << handle_nil(answer.id) if detail_options['comment_id'] == 'true'
    tcsv << handle_nil(answer.comments) if detail_options['comments'] == 'true'
    tcsv << handle_nil(answer.answer) if detail_options['score'] == 'true'
    tcsv
  end


            if @reviewee.nil?
This method generates a hash of answers, which is used to populate the CSV.
              tcsv << ' '
            else
  # Populate answers will review information
              if detail_options['team_name'] == 'true'
  def self.generate_answer(answers, assignment)
                tcsv << @reviewee.name
    # get all response maps for this assignment
              end
    @response_maps_for_assignment = ResponseMap.find_by_sql(["SELECT * FROM response_maps WHERE reviewed_object_id = #{assignment.id}"])
            end
    # for each map, get the response & answer associated with it
    @response_maps_for_assignment.each do |map|
      @response_for_this_map = Response.find_by_sql(["SELECT * FROM responses WHERE map_id = #{map.id}"])
      # for this response, get the answer associated with it
      @response_for_this_map.each do |res_map|
        @answer = Answer.find_by_sql(["SELECT * FROM answers WHERE response_id = #{res_map.id}"])
        @answer.each do |ans|
          answers[res_map.round][map.type].push(ans)
        end
      end
    end
    answers
  end


            if reviewer.nil?
This method checks for number of answers in a particular round/response type and returns nil if there are none since the csv doesn't need to output any header for this round/response type. If this round has some answers then the round number header is generated along with the response type. If the round number is nil, then we simply make the header say 'Round Nill' instead.
              tcsv << ' '
            else
              if detail_options['reviewer'] == 'true'
                tcsv << reviewer.name
              end
            end


            if answer.question.txt.nil?
  # Checks if there are rounds with no reviews
              tcsv << ' '
  def self.check_empty_rounds(answers, round_num, res_type)
            else
    unless answers[round_num][res_type].empty?
              if detail_options['question'] == 'true'
      round_type =
                tcsv << answer.question.txt
        if round_num.nil?
              end
          "Round Nill - " + res_type
            end
        else
 
          "Round " + round_num.to_s + " - " + res_type.to_s
            if answer.question.id.nil?
              tcsv << ' '
            else
              if detail_options['question_id'] == 'true'
                tcsv << answer.question.id
              end
            end
 
            if answer.id.nil?
              tcsv << ' '
            else
              if detail_options['comment_id'] == 'true'
                tcsv << answer.id
              end
            end
 
            if answer.comments.nil?
              tcsv << ' '
            else
              if detail_options['comments'] == 'true'
                tcsv << answer.comments
              end
            end
 
            if answer.answer.nil?
              tcsv << ' '
            else
              if detail_options['score'] == 'true'
                tcsv << answer.answer
              end
            end
 
            csv << tcsv
         end
         end
       end
       return round_type
     end
     end
    nil
   end
   end


This method is called by the controller to set the columns in the csv.


   # This method is used for export detailed contents. - Akshit, Kushagra, Vaibhav
   # This method is used for export detailed contents. - Akshit, Kushagra, Vaibhav
Line 213: Line 183:
   end
   end


This method is called by the controller to set the headers in the csv (including Assignment Name and Instructor)


   # This method is used to set the headers for the csv like Assignment Name and Assignment Instructor
   # This method is used to set the headers for the csv like Assignment Name and Assignment Instructor
Line 224: Line 195:


==Test Plan==
==Test Plan==
'''Flow Chart'''
When exporting a detailed CSV, an instructor can choose to include all, some, or none of the headers and the assignment may or may not include answers. The chart below details possible scenarios.
[[File:OSSTestChart.PNG]]
{| class="wikitable"
|-
| '''Test Type'''      || '''Feature/Integration Test'''
|-
| '''Testing Tool'''      || '''Rspec'''
|-
| '''Scenario 1'''      ||
Export to CSV with all field options enabled and data contains an answer
|-
| '''Test Process Description'''      ||
Before each test case is run, the following factories are created:
  before(:each) do
    @assignment = create(:assignment)
    create(:assignment_team, name: "team1")
    @student = create(:student, name: "student1")
    create(:participant, user: @student)
    create(:questionnaire)
    create(:question)
    create(:review_response_map)
    create(:response)
  end
The following test case is run to check this scenario:
  it "checks_if_csv has the correct data" do
    create(:answer, comments: "Test comment")
    options = {"team_id" => "true", "team_name" => "true",
              "reviewer" => "true", "question" => "true",
              "question_id" => "true", "comment_id" => "true",
              "comments" => "true", "score" => "true"}
    expected_csv = File.read('spec/features/assignment_export_details/expected_details_csv.txt')
    generated_csv = CSV.generate(col_sep: delimiter) do |csv|
      csv << Assignment.export_headers(@assignment.id)
      csv << Assignment.export_details_fields(options)
      Assignment.export_details(csv, @assignment.id, options)
    end
    expect(generated_csv).to eq(expected_csv)
  end
'''The expected CSV file is read in as a text file to simplify string comparison with the generated CSV string.'''
The assignment details and all field headers should be displayed with one answer.
A CSV file with the following content is to be expected:
  Assignment Name: final2,Assignment Instructor: instructor6
  Team ID / Author ID,Team Name / Author Name,Reviewer,Question / Dimension Name,Question ID / Dimension,Comment ID,Comments,Score
  Round 1 - ReviewResponseMap,---,---,---,---,---,---,---
  1,team1,student1,Test question:,1,1,Test comment,1
|-
| '''Scenario 2'''    ||
Export to CSV with some field options enabled and data contains an answer
|-
| '''Test Process Description'''      ||
The following test case is run to check this scenario:
  it "checks csv with some options" do
    create(:answer, comments: "Test comment")
    options = {"team_id" => "false", "team_name" => "true",
              "reviewer" => "true", "question" => "true",
              "question_id" => "false", "comment_id" => "false",
              "comments" => "true", "score" => "true"}
    expected_csv = File.read('spec/features/assignment_export_details/expected_details_some_options_csv.txt')
    generated_csv = CSV.generate(col_sep: delimiter) do |csv|
      csv << Assignment.export_headers(@assignment.id)
      csv << Assignment.export_details_fields(options)
      Assignment.export_details(csv, @assignment.id, options)
    end
    expect(generated_csv).to eq(expected_csv)
  end
The assignment details and all non-ID field headers should be displayed with one answer.
A CSV file with the following content is to be expected:
  Assignment Name: final2,Assignment Instructor: instructor6
  Team Name / Author Name,Reviewer,Question / Dimension Name,Comments,Score
  Round 1 - ReviewResponseMap,---,---,---,---,---,---,---
  team1,student1,Test question:,Test comment,1
|-
| '''Scenario 3'''    ||
Export to CSV with all field options enabled and data contains no answer
|-
| '''Test Process Description'''      ||
The following test case is run to check this scenario:
  it "checks csv with no data" do
    options = {"team_id" => "true", "team_name" => "true",
              "reviewer" => "true", "question" => "true",
              "question_id" => "true", "comment_id" => "true",
              "comments" => "true", "score" => "true"}
    expected_csv = File.read('spec/features/assignment_export_details/expected_details_no_data_csv.txt')
    generated_csv = CSV.generate(col_sep: delimiter) do |csv|
      csv << Assignment.export_headers(@assignment.id)
      csv << Assignment.export_details_fields(options)
      Assignment.export_details(csv, @assignment.id, options)
    end
    expect(generated_csv).to eq(expected_csv)
  end
Only the assignment details and all field headers should be displayed.
A CSV file with the following content is to be expected:
  Assignment Name: final2,Assignment Instructor: instructor6
  Team ID / Author ID,Team Name / Author Name,Reviewer,Question / Dimension Name,Question ID / Dimension,Comment ID,Comments,Score
|-
| '''Scenario 4'''    ||
Export to CSV with no field options enabled and data contains an answer
|-
| '''Test Process Description'''      ||
The following test case is run to check this scenario:
  it "checks csv with data and no options" do
    create(:answer, comments: "Test comment")
    options = {"team_id" => "false", "team_name" => "false",
              "reviewer" => "false", "question" => "false",
              "question_id" => "false", "comment_id" => "false",
              "comments" => "false", "score" => "false"}
    expected_csv = File.read('spec/features/assignment_export_details/expected_details_no_options_csv.txt')
    generated_csv = CSV.generate(col_sep: delimiter) do |csv|
      csv << Assignment.export_headers(@assignment.id)
      csv << Assignment.export_details_fields(options)
      Assignment.export_details(csv, @assignment.id, options)
    end
    expect(generated_csv).to eq(expected_csv)
  end
Only the assignment details should be displayed along with no headers and no answer.
A CSV file with the following content is to be expected:
  Assignment Name: final2,Assignment Instructor: instructor6
|-
| '''Test Type'''      || '''Functional Testing'''
|-
| '''Testing Tool'''      || '''Manual Testing'''
|-
| '''Scenario 5'''    ||
* Go to the deployment link (http://152.46.16.143:3000)
* Log in as an instructor (we used username: instructor6 and password: password)
* Click Manage -> Assignments
* Click on 'View Score' for an assignment (the magnifying glass and star icon)
* Let the page load
* Click 'Export Grade' at the bottom of the page
* The export grades page will load
* Select which columns you want the csv to output and what kind of delimiter
* Click 'Export Details' (CSV should take 1-2 minutes to generate, so please be patient)
'''HINT WHEN TESTING:''' When you click the 'View Score' icon for an assignment, <br>
some assignments take FOREVER to load on the VCL, so please be patient. <br>
However here is a helpful link that will go straight to the export grades page for <br>
Assignment ID 754 Aka Wikipedia Contribution. <br>
http://152.46.16.143:3000/export_file/start?id=754&model=Assignment <br>
|}

Latest revision as of 03:14, 1 April 2017

Introduction

This project is an addendum to the bigger Expertiza project. The Expertiza project is software to create reusable learning objects through peer review. It also supports team projects, and the submission of almost any document type, including URLs and wiki pages.

The requirement for this OSS project was to 'Export Scores In Detail'

Deployment Link

http://152.46.16.143:3000

Branch on Git

The branch on which we developed this project on is called : 'exportdetail'

Problem Statement

Expertiza provides a the ability for an instructor to export scores for an assignment. Whenever a user fills out teammate reviews, peer reviews, feedback reviews, and etc. the scores for each question on those reviews are stored in the database. Currently however Expertiza only exports a csv with aggregated scores which are computed as weighted averages of the scores given in reviews. This is not the most helpful for visualizing the score data by question, individual team/user, reviewer. So that is why our assignment is to implement the ability to export a more detailed csv that contained all the scores for each question for each review and review type within a specific assignment.

After talking with our project contact, Ferry, it was decided that the csv would be organized by round and within each round by response type. Part of the implementation was to also include the ability to choose the delimiter for the csv and specify which columns they wanted to include.

Design

So the reason we implemented our feature a certain way is because there was already previous code for exporting an aggregate csv so we designed our feature in the same fashion. An export controller already existed so we added a new method in that for exporting details and modeled it based on the already existing export method. Assignment.rb already had the methods for setting columns/fields and getting aggregate export info so we added our implementations corresponding methods in that class as well. For the view, we simply added our code, that linked to the new controller method, in the same view where the other csv feature was implemented. No specific design pattern was used, but our feature was simply modeled after previously existing similar features.

Implementation

Files Updated

  • app/controllers/export_file_controller.rb
  • app/models/assignment.rb
  • app/views/export_file/start.html.erb

Files Added

  • app/views/export_file/_export_details.html.erb
  • spec/controllers/export_file_controller_spec.rb
  • spec/features/assignment_export_details/expected_details_csv.txt

Code Snippets

  • export_file_controller_spec.rb

This method is called when the 'Export Details' button is clicked and selects the delimiter and generates the csv with selected columns. It then passes the CSV into the assignment models method to populate it.

def exportdetails
    @delim_type = params[:delim_type2]
    if @delim_type == "comma"
      filename = params[:model] + params[:id] + "_Details.csv"
      delimiter = ","
    elsif @delim_type == "space"
      filename = params[:model] + params[:id] + "_Details.csv"
      delimiter = " "
    elsif @delim_type == "tab"
      filename = params[:model] + params[:id] + "_Details.csv"
      delimiter = "\t"
    elsif @delim_type == "other"
      filename = params[:model] + params[:id] + "_Details.csv"
      delimiter = other_char2
    end
    allowed_models = ['Assignment']
    csv_data = CSV.generate(col_sep: delimiter) do |csv|
     if allowed_models.include? params[:model]
        csv << Object.const_get(params[:model]).export_Headers(params[:id])
        csv << Object.const_get(params[:model]).export_details_fields(params[:details])
        Object.const_get(params[:model]).export_details(csv, params[:id], params[:details])
     end
    end
  
    send_data csv_data,
              type: 'text/csv; charset=iso-8859-1; header=present',
        disposition: "attachment; filename=#{filename}"

 end
  • app/models/assignment.rb

This method is called to populate it the csv and is where the majority of our implementation lies. It finds all the ResponseMaps associated with this assignment, then finds all the Responses associated with that each ResponseMap. Then for each response it saves the Answer objects associated with it into an array that is stored in a hash that is indexed by round and response type (teammate review/feedback review/etc).

 def self.export_details(csv, parent_id, detail_options)
   return csv unless detail_options.value?('true')
   
   @assignment = Assignment.find(parent_id)
   @answers = {} # Contains all answer objects for this assignment
    # Find all unique response types
   @uniq_response_type = ResponseMap.uniq.pluck(:type)
    # Find all unique round numbers
   @uniq_rounds = Response.uniq.pluck(:round)   
    # create the nested hash that holds all the answers organized by round # and response type
   @uniq_rounds.each do |round_num|
     @answers[round_num] = {}
     @uniq_response_type.each do |res_type|
       @answers[round_num][res_type] = []
     end
   end
   @answers = generate_answer(@answers, @assignment)
   # Loop through each round and response type and construct a new row to be pushed in CSV
   @uniq_rounds.each do |round_num|
     @uniq_response_type.each do |res_type|
       round_type = check_empty_rounds(@answers, round_num, res_type)
       unless round_type.nil?
         csv << [round_type, '---', '---', '---', '---', '---', '---', '---']
       end
       @answers[round_num][res_type].each do |answer|
         csv << csv_row(detail_options, answer)
       end
     end
   end
 end

This method checks nil while populating a csv field headers to only add headers which the user selected from the checkboxes.

 def self.handle_nil(csv_field)
   return ' ' if csv_field.nil?
   csv_field
 end

This method generates a CSV row by looping through the answers.

 # Generates a single row based on the detail_options selected 
 def self.csv_row(detail_options, answer)
   tcsv = []
   @response = Response.find_by_id(answer.response_id)
   ans = ResponseMap.find_by_id(@response.map_id)
   @reviewee = Team.find_by_id(ans.reviewee_id)
   @reviewee = Participant.find_by_id(ans.reviewee_id).user if @reviewee.nil?
   reviewer = Participant.find_by_id(ans.reviewer_id).user
   tcsv << handle_nil(@reviewee.id) if detail_options['team_id'] == 'true'
   tcsv << handle_nil(@reviewee.name) if detail_options['team_name'] == 'true'
   tcsv << handle_nil(reviewer.name) if detail_options['reviewer'] == 'true'
   tcsv << handle_nil(answer.question.txt) if detail_options['question'] == 'true'
   tcsv << handle_nil(answer.question.id) if detail_options['question_id'] == 'true'
   tcsv << handle_nil(answer.id) if detail_options['comment_id'] == 'true'
   tcsv << handle_nil(answer.comments) if detail_options['comments'] == 'true'
   tcsv << handle_nil(answer.answer) if detail_options['score'] == 'true'
   tcsv
 end

This method generates a hash of answers, which is used to populate the CSV.

 # Populate answers will review information
 def self.generate_answer(answers, assignment)
   # get all response maps for this assignment
   @response_maps_for_assignment = ResponseMap.find_by_sql(["SELECT * FROM response_maps WHERE reviewed_object_id = #{assignment.id}"]) 
   # for each map, get the response & answer associated with it
   @response_maps_for_assignment.each do |map|
     @response_for_this_map = Response.find_by_sql(["SELECT * FROM responses WHERE map_id = #{map.id}"])
     # for this response, get the answer associated with it
     @response_for_this_map.each do |res_map|
       @answer = Answer.find_by_sql(["SELECT * FROM answers WHERE response_id = #{res_map.id}"])
       @answer.each do |ans|
         answers[res_map.round][map.type].push(ans)
       end
     end
   end
   answers
 end

This method checks for number of answers in a particular round/response type and returns nil if there are none since the csv doesn't need to output any header for this round/response type. If this round has some answers then the round number header is generated along with the response type. If the round number is nil, then we simply make the header say 'Round Nill' instead.

 # Checks if there are rounds with no reviews
 def self.check_empty_rounds(answers, round_num, res_type)
   unless answers[round_num][res_type].empty?
     round_type =
       if round_num.nil?
         "Round Nill - " + res_type
       else
         "Round " + round_num.to_s + " - " + res_type.to_s
       end
     return round_type
   end
   nil
 end

This method is called by the controller to set the columns in the csv.

 # This method is used for export detailed contents. - Akshit, Kushagra, Vaibhav
 def self.export_details_fields(detail_options)
   fields = []
   fields << 'Team ID / Author ID' if detail_options['team_id'] == 'true'       
   fields << 'Team Name / Author Name' if detail_options['team_name'] == 'true' 
   fields << 'Reviewer' if detail_options['reviewer'] == 'true'    
   fields << 'Question / Dimension Name' if detail_options['question'] == 'true'
   fields << 'Question ID / Dimension' if detail_options['question_id'] == 'true'
   fields << 'Comment ID' if detail_options['comment_id'] == 'true'   
   fields << 'Comments' if detail_options['comments'] == 'true'      
   fields << 'Score' if detail_options['score'] == 'true'  
   fields
 end

This method is called by the controller to set the headers in the csv (including Assignment Name and Instructor)

 # This method is used to set the headers for the csv like Assignment Name and Assignment Instructor
 def self.export_Headers(parent_id)
   @assignment = Assignment.find(parent_id)
   fields = []
   fields << "Assignment Name: " + @assignment.name.to_s
   fields << "Assignment Instructor: " + User.find(@assignment.instructor_id).name.to_s
   fields
 end

Test Plan

Flow Chart

When exporting a detailed CSV, an instructor can choose to include all, some, or none of the headers and the assignment may or may not include answers. The chart below details possible scenarios.

Test Type Feature/Integration Test
Testing Tool Rspec
Scenario 1

Export to CSV with all field options enabled and data contains an answer

Test Process Description

Before each test case is run, the following factories are created:

 before(:each) do
   @assignment = create(:assignment)
   create(:assignment_team, name: "team1")
   @student = create(:student, name: "student1")
   create(:participant, user: @student)
   create(:questionnaire)
   create(:question)
   create(:review_response_map)
   create(:response)
 end

The following test case is run to check this scenario:

 it "checks_if_csv has the correct data" do
   create(:answer, comments: "Test comment")
   options = {"team_id" => "true", "team_name" => "true",
              "reviewer" => "true", "question" => "true",
              "question_id" => "true", "comment_id" => "true",
              "comments" => "true", "score" => "true"}
   expected_csv = File.read('spec/features/assignment_export_details/expected_details_csv.txt')
   generated_csv = CSV.generate(col_sep: delimiter) do |csv|
     csv << Assignment.export_headers(@assignment.id)
     csv << Assignment.export_details_fields(options)
     Assignment.export_details(csv, @assignment.id, options)
   end
   expect(generated_csv).to eq(expected_csv)
 end

The expected CSV file is read in as a text file to simplify string comparison with the generated CSV string.

The assignment details and all field headers should be displayed with one answer. A CSV file with the following content is to be expected:

 Assignment Name: final2,Assignment Instructor: instructor6
 Team ID / Author ID,Team Name / Author Name,Reviewer,Question / Dimension Name,Question ID / Dimension,Comment ID,Comments,Score
 Round 1 - ReviewResponseMap,---,---,---,---,---,---,---
 1,team1,student1,Test question:,1,1,Test comment,1
Scenario 2

Export to CSV with some field options enabled and data contains an answer

Test Process Description

The following test case is run to check this scenario:

 it "checks csv with some options" do
   create(:answer, comments: "Test comment")
   options = {"team_id" => "false", "team_name" => "true",
              "reviewer" => "true", "question" => "true",
              "question_id" => "false", "comment_id" => "false",
              "comments" => "true", "score" => "true"}
   expected_csv = File.read('spec/features/assignment_export_details/expected_details_some_options_csv.txt')
   generated_csv = CSV.generate(col_sep: delimiter) do |csv|
     csv << Assignment.export_headers(@assignment.id)
     csv << Assignment.export_details_fields(options)
     Assignment.export_details(csv, @assignment.id, options)
   end
   expect(generated_csv).to eq(expected_csv)
 end

The assignment details and all non-ID field headers should be displayed with one answer. A CSV file with the following content is to be expected:

 Assignment Name: final2,Assignment Instructor: instructor6
 Team Name / Author Name,Reviewer,Question / Dimension Name,Comments,Score
 Round 1 - ReviewResponseMap,---,---,---,---,---,---,---
 team1,student1,Test question:,Test comment,1
Scenario 3

Export to CSV with all field options enabled and data contains no answer

Test Process Description

The following test case is run to check this scenario:

 it "checks csv with no data" do
   options = {"team_id" => "true", "team_name" => "true",
              "reviewer" => "true", "question" => "true",
              "question_id" => "true", "comment_id" => "true",
              "comments" => "true", "score" => "true"}
   expected_csv = File.read('spec/features/assignment_export_details/expected_details_no_data_csv.txt')
   generated_csv = CSV.generate(col_sep: delimiter) do |csv|
     csv << Assignment.export_headers(@assignment.id)
     csv << Assignment.export_details_fields(options)
     Assignment.export_details(csv, @assignment.id, options)
   end
   expect(generated_csv).to eq(expected_csv)
 end

Only the assignment details and all field headers should be displayed. A CSV file with the following content is to be expected:

 Assignment Name: final2,Assignment Instructor: instructor6
 Team ID / Author ID,Team Name / Author Name,Reviewer,Question / Dimension Name,Question ID / Dimension,Comment ID,Comments,Score
Scenario 4

Export to CSV with no field options enabled and data contains an answer

Test Process Description

The following test case is run to check this scenario:

 it "checks csv with data and no options" do
   create(:answer, comments: "Test comment")
   options = {"team_id" => "false", "team_name" => "false",
              "reviewer" => "false", "question" => "false",
              "question_id" => "false", "comment_id" => "false",
              "comments" => "false", "score" => "false"}
   expected_csv = File.read('spec/features/assignment_export_details/expected_details_no_options_csv.txt')
   generated_csv = CSV.generate(col_sep: delimiter) do |csv|
     csv << Assignment.export_headers(@assignment.id)
     csv << Assignment.export_details_fields(options)
     Assignment.export_details(csv, @assignment.id, options)
   end
   expect(generated_csv).to eq(expected_csv)
 end

Only the assignment details should be displayed along with no headers and no answer. A CSV file with the following content is to be expected:

 Assignment Name: final2,Assignment Instructor: instructor6
Test Type Functional Testing
Testing Tool Manual Testing
Scenario 5
  • Go to the deployment link (http://152.46.16.143:3000)
  • Log in as an instructor (we used username: instructor6 and password: password)
  • Click Manage -> Assignments
  • Click on 'View Score' for an assignment (the magnifying glass and star icon)
  • Let the page load
  • Click 'Export Grade' at the bottom of the page
  • The export grades page will load
  • Select which columns you want the csv to output and what kind of delimiter
  • Click 'Export Details' (CSV should take 1-2 minutes to generate, so please be patient)

HINT WHEN TESTING: When you click the 'View Score' icon for an assignment,
some assignments take FOREVER to load on the VCL, so please be patient.
However here is a helpful link that will go straight to the export grades page for
Assignment ID 754 Aka Wikipedia Contribution.

http://152.46.16.143:3000/export_file/start?id=754&model=Assignment