E1850. Write unit tests for review response map.rb team100: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
(38 intermediate revisions by 2 users not shown)
Line 2: Line 2:


== Background ==
== Background ==
Expertiza is an open source web based peer review system developed and maintained by students and faculty members at North Carolina State University. It enables students enrolled in a particular course to form online teams, complete assignments, review other's work and receive feedbacks of your work.
Expertiza is an open source web based on peer review system developed and maintained by students and faculty members at North Carolina State University. It enables students who enrolled in a particular course to form online teams, complete assignments, review other's work and receive feedbacks of their works.


== Problem ==
== Problem ==
Line 10: Line 10:
*Create a new file named review_response_map_spec.rb under spec/models folder
*Create a new file named review_response_map_spec.rb under spec/models folder
*Write RSpec unit tests to make the path coverage above 90%.
*Write RSpec unit tests to make the path coverage above 90%.
*Coverage as many edge cases as we can.
*Coverage edge cases.
*Achieve as high branch coverage as we can. Use the mutant-rspec gem to measure test thoroughness and fault-finding capability of our tests.
*Achieve high branch coverage. Use the mutant-rspec gem to measure test thoroughness and fault-finding capability of tests.


== Files Created ==
== Files Created ==
Line 17: Line 17:


== Test Plan ==
== Test Plan ==
=== Setup expertiza environment===
Follow the instruction on http://wiki.expertiza.ncsu.edu/index.php/Development:Setup:OSX#Get_Expertiza
=== Model functions ===
To better test the methods, we read the whole review response map model and understand the functionalities of what we want to test.
:*Questionnaire: find the specific questionnaire.
:*Get title: set the title.
:*Delete: delete the feedback response map and metareview response map.
:*Export fields: set the fields of export.
:*Export: export the review response map.
:*Import: import the review response map from local.
:*Show feedback: show the feedback via html.
:*Metareview response maps: fetch all the metareview response map and return.
:*Get responses for team round: get the responses for given round.
:*Final versions from reviewer: return the final review version from reviewers.
:*Review response report: find the reviewers for a given assignment.
:*Email: send an email to the members in a team.
:*Prepare final review versions: prepare the final review versions for an assignment.
:*Prepare review response: return the review responses id for an assignment.
=== Mock instance ===
=== Mock instance ===
We mock the necessary instances for the test in the beginning of test file.
We mock the necessary instances for the test in the beginning of test file.
Line 24: Line 58:
   let(:review_response_map) { build(:review_response_map, id: 1, assignment: assignment, reviewer: participant, reviewee: team, reviewed_object_id: 1) }
   let(:review_response_map) { build(:review_response_map, id: 1, assignment: assignment, reviewer: participant, reviewee: team, reviewed_object_id: 1) }
   let(:review_response_map1) { build(:review_response_map, id: 2, assignment: assignment, reviewer: participant1, reviewee: team1, reviewed_object_id: 1) }
   let(:review_response_map1) { build(:review_response_map, id: 2, assignment: assignment, reviewer: participant1, reviewee: team1, reviewed_object_id: 1) }
  let(:feed_back_response_map) { double('feed_back_response_map', reviewed_object_id: 1) }
   let(:feedback) { FeedbackResponseMap.new(id: 1, reviewed_object_id: 1, reviewer_id: 1, reviewee_id: 1) }
   let(:feedback) { FeedbackResponseMap.new(id: 1, reviewed_object_id: 1, reviewer_id: 1, reviewee_id: 1) }
   let(:participant) { build(:participant, id: 1, parent_id: 1, user: build(:student, parent_id: 1, name: 'no name', fullname: 'no one')) }
   let(:participant) { build(:participant, id: 1, parent_id: 1, user: build(:student, parent_id: 1, name: 'no name', fullname: 'no one')) }
   let(:participant1) { build(:participant, id: 2, parent_id: 2, user: build(:student, parent_id: 1, name: 'has name', fullname: 'has one')) }
   let(:participant1) { build(:participant, id: 2, parent_id: 2, user: build(:student, parent_id: 1, name: 'has name', fullname: 'has one')) }
  let(:questionnaire) { ReviewQuestionnaire.new(id: 1, questions: [question], max_question_score: 5) }
   let(:assignment) { build(:assignment, id: 1, name: 'Test Assgt', rounds_of_reviews: 2) }
  let(:questionnaire1) { Questionnaire.new(id: 1, type: 'ReviewQuestionnaire') }
   let(:assignment1) { build(:assignment, id: 2, name: 'Test Assgt', rounds_of_reviews: 1) }
   let(:assignment) { build(:assignment, id: 1, name: 'Test Assgt', rounds_of_reviews: 2 ) }
   let(:response) { build(:response, id: 1, map_id: 1, round: 1, response_map: review_response_map, is_submitted: true) }
   let(:assignment1) { build(:assignment, id: 2, name: 'Test Assgt', rounds_of_reviews: 1 ) }
   let(:response1) { build(:response, id: 2, map_id: 1, round: 2, response_map: review_response_map) }
   let(:response) { build(:response, id: 1, map_id: 1, round: 1, response_map: review_response_map, scores: [answer], is_submitted: true) }
   let(:response2) { build(:response, id: 3, map_id: 1, round: nil, response_map: review_response_map, is_submitted: true) }
   let(:response1) { build(:response, id: 2, map_id: 1, round: 2, response_map: review_response_map, scores: [answer]) }
   let(:metareview_response_map) { MetareviewResponseMap.new(reviewed_object_id: 1) }
   let(:response2) { build(:response, id: 3, map_id: 1, round: nil, response_map: review_response_map, scores: [answer], is_submitted: true) }
   let(:student) { build(:student, id: 1, fullname: 'no one', email: 'expertiza@mailinator.com') }
  let(:answer) { Answer.new(answer: 1, comments: 'Answer text', question_id: 1) }
   let(:questionnaire) { Questionnaire.new(id: 1, type: 'ReviewQuestionnaire') }
  let(:question) { Criterion.new(id: 1, weight: 2, break_before: true) }
   let(:metareview_response_map) { double('metareviewmap')}
  let(:metareview_response_map1) { MetareviewResponseMap.new(reviewed_object_id: 1)}
   let(:student) {build(:student, id: 1, fullname: 'no one', email: 'expertiza@mailinator.com') }
   let(:assignment_questionnaire){ AssignmentQuestionnaire.new(assignment_id: 1, used_in_round: 1, questionnaire_id: 1) }
  let(:assignment_questionnaire1){ AssignmentQuestionnaire.new(assignment_id: 1, used_in_round: 2, questionnaire_id: 1) }
   let(:response_map) { ResponseMap.new(id: 1, reviewed_object_id: 1, reviewee_id: 1, reviewer_id: 1, type: "ReviewResponseMap", response: [response], calibrate_to: 0) }
   let(:response_map) { ResponseMap.new(id: 1, reviewed_object_id: 1, reviewee_id: 1, reviewer_id: 1, type: "ReviewResponseMap", response: [response], calibrate_to: 0) }
   let(:user) {User.new(id:1 , name: "name", fullname: 'fullname') }
   let(:user) { User.new(id: 1, name: "name", fullname: 'fullname') }
   let(:user1) { User.new(id: 2, name: "name1", fullname: 'fullname') }
   let(:user1) { User.new(id: 2, name: "name1", fullname: 'fullname') }
   let(:assignment_participant) { AssignmentParticipant.new(user_id: 1, parent_id: 1) }
   let(:assignment_participant) { AssignmentParticipant.new(user_id: 1, parent_id: 1) }
   let(:assignment_participant1) { AssignmentParticipant.new(id: 1, user_id: 2, parent_id: 1) }
   let(:assignment_participant1) { AssignmentParticipant.new(id: 1, user_id: 2, parent_id: 1) }
  let(:teams_users) {TeamsUser.new(user_id: 1, team_id: 1)}
</pre>
</pre>
== Implementation ==
Write test for the methods in review_response_map.rb.


=== Questionnaire ===
=== Questionnaire ===
Questionnaire returns a questionnaire associated with an assignment.
Questionnaire method returns a questionnaire associated with an assignment.
<pre>
<pre>
   it '#questionnaire' do
   it '#questionnaire' do
     round = 1
     round = 1
     allow(assignment).to receive(:review_questionnaire_id).with(1).and_return(1)
     allow(assignment).to receive(:review_questionnaire_id).and_return(1)
     allow(Questionnaire).to receive(:find_by).with(id: 1).and_return(questionnaire1)
     allow(Questionnaire).to receive(:find_by).with(id: 1).and_return(questionnaire)
     expect(review_response_map.questionnaire(1)).to eq(questionnaire1)
     expect(review_response_map.questionnaire(1)).to eq(questionnaire)
   end
   end
</pre>
</pre>


=== Get title ===
=== Get title ===
Get_title returns the title.
Get_title method returns the title.
<pre>
<pre>
   it '#get_title' do
   it '#get_title' do
Line 70: Line 99:


=== Delete ===
=== Delete ===
<pre>
Delete method deletes the feedback_response_map and metareview_response_map and return review_response_map.
  def delete(_force = nil)
    fmaps = FeedbackResponseMap.where(reviewed_object_id: self.response.response_id)
    fmaps.each(&:destroy)
    maps = MetareviewResponseMap.where(reviewed_object_id: self.id)
    maps.each(&:destroy)
    self.destroy
  end
</pre>
Test the delete method of review_response_map which contains delete feedback_response_map.
<pre>
<pre>
   it '#delete' do
   it '#delete' do
     allow(Response).to receive(:find).and_return(response)
     allow(Response).to receive(:find).and_return(response)
     allow(FeedbackResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([feedback])
     allow(FeedbackResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([feedback])
     allow(MetareviewResponseMap).to receive(:where).and_return([metareview_response_map1])
     allow(MetareviewResponseMap).to receive(:where).and_return([metareview_response_map])
     expect(review_response_map.delete).to equal(review_response_map)
     expect(review_response_map.delete).to equal(review_response_map)
   end
   end
Line 90: Line 110:


=== Export fields ===
=== Export fields ===
<pre>
Export_fields method which shows the title of export csv file, "contributor" and "reviewed by".
  def self.export_fields(_options)
    ["contributor", "reviewed by"]
  end
</pre>
Test the export_fields method which show the title of export csv file should be "contributor" and "reviewed by".
<pre>
<pre>
   it '#export_fields' do
   it '#export_fields' do
     expect(ReviewResponseMap.export_fields('Missing "_options"')).to eq(["contributor", "reviewed by"])
     expect(ReviewResponseMap.export_fields(options)).to eq(["contributor", "reviewed by"])
   end
   end
</pre>
</pre>


=== Export ===
=== Export ===
<pre>
Export method exports the name of reviewer and reviewee and return the map.
  def self.export(csv, parent_id, _options)
    mappings = where(reviewed_object_id: parent_id).to_a
    mappings.sort! {|a, b| a.reviewee.name <=> b.reviewee.name }
    mappings.each do |map|
      csv << [
        map.reviewee.name,
        map.reviewer.name
      ]
    end
  end
</pre>
Test the export method.
<pre>
<pre>
   it '#export' do
   it '#export' do
     csv = []
     csv = []
     parent_id = 1
     parent_id = 1
     _options = _options
     options = nil
     allow(ReviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([review_response_map, review_response_map1])
     allow(ReviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([review_response_map, review_response_map1])
     expect(ReviewResponseMap.export(csv, parent_id, _options)).to eq([review_response_map1, review_response_map])
     expect(ReviewResponseMap.export(csv, parent_id, options)).to eq([review_response_map1, review_response_map])
   end
   end
</pre>
</pre>


=== Import ===
=== Import ===
Import method allows user to import the csv file and check it. After that, it returns the name of reviewers.
<pre>
<pre>
   def self.import(row_hash, _session, assignment_id)
   it '#import' do
     reviewee_user_name = row_hash[:reviewee].to_s
     row_hash = {reviewee: "name", reviewers: ["name1"]}
    reviewee_user = User.find_by(name: reviewee_user_name)
     session = nil
    raise ArgumentError, "Cannot find reviewee user." unless reviewee_user
     assignment_id = 1
    reviewee_participant = AssignmentParticipant.find_by(user_id: reviewee_user.id, parent_id: assignment_id)
</pre>
    raise ArgumentError, "Reviewee user is not a participant in this assignment." unless reviewee_participant
 
     reviewee_team = AssignmentTeam.team(reviewee_participant)
When reviewee user = nil
     if reviewee_team.nil? # lazy team creation: if the reviewee does not have team, create one.
 
      reviewee_team = AssignmentTeam.create(name: 'Team' + '_' + rand(1000).to_s,
<pre>
                                            parent_id: assignment_id, type: 'AssignmentTeam')
    allow(User).to receive(:find_by).and_return(nil)
      t_user = TeamsUser.create(team_id: reviewee_team.id, user_id: reviewee_user.id)
    expect { ReviewResponseMap.import(row_hash, session, 1) }.to raise_error(ArgumentError, message = "Cannot find reviewee user.")
      team_node = TeamNode.create(parent_id: assignment_id, node_object_id: reviewee_team.id)
      TeamUserNode.create(parent_id: team_node.id, node_object_id: t_user.id)
    end
    row_hash[:reviewers].each do |reviewer|
      reviewer_user_name = reviewer.to_s
      reviewer_user = User.find_by(name: reviewer_user_name)
      raise ArgumentError, "Cannot find reviewer user." unless reviewer_user
      next if reviewer_user_name.empty?
      reviewer_participant = AssignmentParticipant.find_by(user_id: reviewer_user.id, parent_id: assignment_id)
      raise ArgumentError, "Reviewer user is not a participant in this assignment." unless reviewer_participant
      ReviewResponseMap.find_or_create_by(reviewed_object_id: assignment_id,
                                          reviewer_id: reviewer_participant.id,
                                          reviewee_id: reviewee_team.id,
                                          calibrate_to: false)
    end
  end
</pre>
</pre>
Test the import method which includes errors casued by various reasons.
 
When reviewee user exists but reviewee user is not a participant in this assignment.
 
<pre>
<pre>
  it '#import' do
    row_hash={reviewee: "name", reviewers: ["name1"]}
    _session = nil
    assignment_id = 1
     allow(User).to receive(:find_by).with(name: "name").and_return(user)
     allow(User).to receive(:find_by).with(name: "name").and_return(user)
    allow(AssignmentParticipant).to receive(:find_by).with(user_id: 1, parent_id: 1).and_return(nil)
    expect { ReviewResponseMap.import(row_hash, session, 1) }.to raise_error(ArgumentError, message = "Reviewee user is not a participant in this assignment.")
</pre>
When reviewee user exists and reviewee user is a participant in this assignment.
<pre>
     allow(AssignmentParticipant).to receive(:find_by).with(user_id: 1, parent_id: 1).and_return(assignment_participant)
     allow(AssignmentParticipant).to receive(:find_by).with(user_id: 1, parent_id: 1).and_return(assignment_participant)
     allow(AssignmentTeam).to receive(:team).with(assignment_participant).and_return(team)
     allow(AssignmentTeam).to receive(:team).with(assignment_participant).and_return(team)
</pre>
When reviewer user doesn't exist.
<pre>
    allow(User).to receive(:find_by).with(name: "name1").and_return(nil)
    expect { ReviewResponseMap.import(row_hash, session, 1) }.to raise_error(ArgumentError, message = "Cannot find reviewer user.")
</pre>
When reviewer user exists.
<pre>
     allow(User).to receive(:find_by).with(name: "name1").and_return(user1)
     allow(User).to receive(:find_by).with(name: "name1").and_return(user1)
</pre>
When reviewer user is not a participant in this assignment.
<pre>
    allow(AssignmentParticipant).to receive(:find_by).with(user_id: 2, parent_id: 1).and_return(nil)
    expect { ReviewResponseMap.import(row_hash, session, 1) }.to raise_error(ArgumentError, message = "Reviewer user is not a participant in this assignment.")
</pre>
When reviewer user is a participant in this assignment.
<pre>
     allow(AssignmentParticipant).to receive(:find_by).with(user_id: 2, parent_id: 1).and_return(assignment_participant1)
     allow(AssignmentParticipant).to receive(:find_by).with(user_id: 2, parent_id: 1).and_return(assignment_participant1)
     allow(ReviewResponseMap).to receive(:find_or_create_by).with(reviewed_object_id: 1, reviewer_id: 1, reviewee_id: 1, calibrate_to: false).and_return(review_response_map)
     allow(ReviewResponseMap).to receive(:find_or_create_by).with(reviewed_object_id: 1, reviewer_id: 1, reviewee_id: 1, calibrate_to: false).and_return(review_response_map)
     expect(ReviewResponseMap.import(row_hash, _session, 1)).to eq(["name1"])
     expect(ReviewResponseMap.import(row_hash, session, 1)).to eq(["name1"])
    # when reviewee_team = nil
</pre>
 
When reviewee_team = nil
 
<pre>
     allow(AssignmentTeam).to receive(:team).with(assignment_participant).and_return(nil)
     allow(AssignmentTeam).to receive(:team).with(assignment_participant).and_return(nil)
     allow(AssignmentTeam).to receive(:create).and_return(double('team', id: 1))
     allow(AssignmentTeam).to receive(:create).and_return(double('team', id: 1))
Line 178: Line 198:
     allow(AssignmentParticipant).to receive(:find_by).with(user_id: 2, parent_id: 1).and_return(assignment_participant1)
     allow(AssignmentParticipant).to receive(:find_by).with(user_id: 2, parent_id: 1).and_return(assignment_participant1)
     allow(ReviewResponseMap).to receive(:find_or_create_by).with(reviewed_object_id: 1, reviewer_id: 1, reviewee_id: 1, calibrate_to: false).and_return(review_response_map)
     allow(ReviewResponseMap).to receive(:find_or_create_by).with(reviewed_object_id: 1, reviewer_id: 1, reviewee_id: 1, calibrate_to: false).and_return(review_response_map)
     expect(ReviewResponseMap.import(row_hash, _session, 1)).to eq(["name1"])
     expect(ReviewResponseMap.import(row_hash, session, 1)).to eq(["name1"])
   end
   end
</pre>
</pre>


=== Show feedback ===
=== Show feedback ===
Show_feedback method returns the html associated with response.
<pre>
<pre>
  def show_feedback(response)
     it '#show_feedback' do
     return unless self.response.any? and response
      allow(review_response_map).to receive(:response).and_return([response])
    map = FeedbackResponseMap.find_by(reviewed_object_id: response.id)
      allow(Response).to receive(:find).and_return(response)
    return map.response.last.display_as_html if map and map.response.any?
      allow(FeedbackResponseMap).to receive(:find_by).with(reviewed_object_id: 1).and_return(feedback)
  end
      allow(feedback).to receive(:response).and_return([response])
</pre>
      expect(review_response_map.show_feedback(response)).to eq("<table width=\"100%\"><tr><td align=\"left\" width=\"70%\"><b>Review </b>"\
Test show_feedback method.
<pre>
  it '#show_feedback' do
    allow(review_response_map).to receive(:response).and_return([response])
    allow(Response).to receive(:find).and_return(response)
    allow(FeedbackResponseMap).to receive(:find_by).with(reviewed_object_id: 1).and_return(feedback)
    allow(feedback).to receive(:response).and_return([response])
    expect(review_response_map.show_feedback(response)).to eq("<table width=\"100%\"><tr><td align=\"left\" width=\"70%\"><b>Review </b>"\
           "&nbsp;&nbsp;&nbsp;<a href=\"#\" name= \"review_1Link\" onClick=\"toggleElement('review_1','review');return false;\">"\
           "&nbsp;&nbsp;&nbsp;<a href=\"#\" name= \"review_1Link\" onClick=\"toggleElement('review_1','review');return false;\">"\
           "show review</a></td><td align=\"left\"><b>Last Reviewed:</b><span>Not available</span></td></tr></table><table id=\"review_1\""\
           "show review</a></td><td align=\"left\"><b>Last Reviewed:</b><span>Not available</span></td></tr></table><table id=\"review_1\""\
           " style=\"display: none;\" class=\"table table-bordered\"><tr><td><b>"\
           " style=\"display: none;\" class=\"table table-bordered\"><tr><td><b>"\
           "Additional Comment: </b></td></tr></table>")
           "Additional Comment: </b></td></tr></table>")
  end
    end
</pre>
</pre>


=== Metareview response maps ===
=== Metareview response maps ===
<pre>
Metareview_response_maps method returns metareview_list associated with responses.
  def metareview_response_maps
    responses = Response.where(map_id: self.id)
    metareview_list = []
    responses.each do |response|
      metareview_response_maps = MetareviewResponseMap.where(reviewed_object_id: response.id)
      metareview_response_maps.each {|metareview_response_map| metareview_list << metareview_response_map }
    end
    metareview_list
  end
</pre>
Test metareview_response_maps method.
<pre>
<pre>
   it '#metareview_response_maps' do
   it '#metareview_response_maps' do
     allow(Response).to receive(:where).with(map_id: 1).and_return([response])
     allow(Response).to receive(:where).with(map_id: 1).and_return([response])
     allow(MetareviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([metareview_response_map1])
     allow(MetareviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([metareview_response_map])
     expect(review_response_map.metareview_response_maps).to eq([metareview_response_map1])
     expect(review_response_map.metareview_response_maps).to eq([metareview_response_map])
   end
   end
</pre>
</pre>


=== Get responses for team round ===
=== Get responses for team round ===
<pre>
Get_responses_for_team_round method returns the responses associated with team and round.
  def self.get_responses_for_team_round(team, round)
    responses = []
    if team.id
      maps = ResponseMap.where(reviewee_id: team.id, type: "ReviewResponseMap")
      maps.each do |map|
        if map.response.any? and map.response.reject {|r| (r.round != round || !r.is_submitted) }.any?
          responses << map.response.reject {|r| (r.round != round || !r.is_submitted) }.last
        end
      end
      responses.sort! {|a, b| a.map.reviewer.fullname <=> b.map.reviewer.fullname }
    end
    responses
  end
</pre>
Test get_responses_for_team_round method.
<pre>
<pre>
   it '#get_responses_for_team_round' do
   it '#get_responses_for_team_round' do
     allow(Team).to receive(:find).and_return(team)
     allow(Team).to receive(:find).and_return(team)
    allow(team).to receive(:id).and_return(1)
     round = 1
     round = 1
     allow(ResponseMap).to receive(:where).with(reviewee_id: team.id, type: "ReviewResponseMap").and_return([response_map])
     allow(ResponseMap).to receive(:where).with(reviewee_id: team.id, type: "ReviewResponseMap").and_return([response_map])
Line 254: Line 240:


=== Final versions from reviewer ===
=== Final versions from reviewer ===
<pre>
Final_versions_from_reviewer method returns the questionnaire and response ids associated with reviewer.
  def self.final_versions_from_reviewer(reviewer_id)
    maps = ReviewResponseMap.where(reviewer_id: reviewer_id)
    assignment = Assignment.find(Participant.find(reviewer_id).parent_id)
    prepare_final_review_versions(assignment, maps)
  end
</pre>
Test final_versions_from_reviewer method.
<pre>
<pre>
   it '#final_versions_from_reviewer' do
   it '#final_versions_from_reviewer' do
Line 273: Line 252:
     allow(Response).to receive(:where).with(map_id: 1, round: 2).and_return([response1])
     allow(Response).to receive(:where).with(map_id: 1, round: 2).and_return([response1])
     allow(assignment).to receive(:review_questionnaire_id).with(2).and_return(1)
     allow(assignment).to receive(:review_questionnaire_id).with(2).and_return(1)
     expect(ReviewResponseMap.final_versions_from_reviewer(1)).to eq({"review round1":{questionnaire_id: 1, response_ids:[1]}, "review round2":{questionnaire_id: 1, response_ids:[2] }})
     expect(ReviewResponseMap.final_versions_from_reviewer(1)).to eq("review round1": {questionnaire_id: 1, response_ids: [1]}, "review round2": {questionnaire_id: 1, response_ids: [2]})
   end
   end
</pre>
</pre>


=== Review response report ===
=== Review response report ===
<pre>
Review_response_report method returns the participants associated with assignment.
  def self.review_response_report(id, assignment, type, review_user)
    if review_user.nil?
      # This is not a search, so find all reviewers for this assignment
      response_maps_with_distinct_participant_id =
        ResponseMap.select("DISTINCT reviewer_id").where('reviewed_object_id = ? and type = ? and calibrate_to = ?', id, type, 0)
      @reviewers = []
      response_maps_with_distinct_participant_id.each do |reviewer_id_from_response_map|
        @reviewers << AssignmentParticipant.find(reviewer_id_from_response_map.reviewer_id)
      end
      @reviewers = Participant.sort_by_name(@reviewers)
    else
      # This is a search, so find reviewers by user's full name
      user_ids = User.select("DISTINCT id").where('fullname LIKE ?', '%' + review_user[:fullname] + '%')
      @reviewers = AssignmentParticipant.where('user_id IN (?) and parent_id = ?', user_ids, assignment.id)
    end
    # @review_scores[reveiwer_id][reviewee_id] = score for assignments not using vary_rubric_by_rounds feature
    # @review_scores[reviewer_id][round][reviewee_id] = score for assignments using vary_rubric_by_rounds feature
  end
</pre>
Test review_response_report method.
<pre>
<pre>
   it '#review_response_report' do
   it '#review_response_report' do
Line 305: Line 264:
     reviewer_id = 1
     reviewer_id = 1
     user_ids = []
     user_ids = []
</pre>
When review user exists.
<pre>
     review_user = user
     review_user = user
     allow(Participant).to receive(:find).with(1).and_return(participant)
     allow(Participant).to receive(:find).with(1).and_return(participant)
Line 310: Line 273:
     allow(User).to receive_message_chain(:select, :where).and_return([user])
     allow(User).to receive_message_chain(:select, :where).and_return([user])
     allow(AssignmentParticipant).to receive(:where).and_return([assignment_participant])
     allow(AssignmentParticipant).to receive(:where).and_return([assignment_participant])
     expect(ReviewResponseMap.review_response_report(id, Assignment.find(Participant.find(reviewer_id).parent_id), type, review_user)).to eq( [assignment_participant] )
     expect(ReviewResponseMap.review_response_report(id, Assignment.find(Participant.find(reviewer_id).parent_id), type, review_user)).to eq([assignment_participant])
</pre>
 
When review user doesn't exists.
<pre>
     review_user = nil
     review_user = nil
     allow(ResponseMap).to receive_message_chain(:select, :where).and_return([response_map])
     allow(ResponseMap).to receive_message_chain(:select, :where).and_return([response_map])
Line 316: Line 283:
     allow(AssignmentParticipant).to receive(:find).with(1).and_return([assignment_participant])
     allow(AssignmentParticipant).to receive(:find).with(1).and_return([assignment_participant])
     allow(Participant).to receive(:sort_by_name).and_return([assignment_participant])
     allow(Participant).to receive(:sort_by_name).and_return([assignment_participant])
     expect(ReviewResponseMap.review_response_report(id, Assignment.find(Participant.find(reviewer_id).parent_id), type, review_user)).to eq( [assignment_participant] )
     expect(ReviewResponseMap.review_response_report(id, Assignment.find(Participant.find(reviewer_id).parent_id), type, review_user)).to eq([assignment_participant])
   end
   end
</pre>
</pre>


=== Email ===
=== Email ===
<pre>
Email method can successfully send an email.
  def email(defn, _participant, assignment)
    defn[:body][:type] = "Peer Review"
    AssignmentTeam.find(reviewee_id).users.each do |user|
      defn[:body][:obj_name] = assignment.name
      defn[:body][:first_name] = User.find(user.id).fullname
      defn[:to] = User.find(user.id).email
      Mailer.sync_message(defn).deliver_now
    end
  end
</pre>
Test email method which can successfully send an email.
<pre>
<pre>
   it '#email' do
   it '#email' do
Line 343: Line 299:
     review_response_map.reviewee_id = 1
     review_response_map.reviewee_id = 1
     defn = {body: {type: "Peer Review", obj_name: "Test Assgt", first_name: "no one", partial_name: "new_submission"}, to: "expertiza@mailinator.com"}
     defn = {body: {type: "Peer Review", obj_name: "Test Assgt", first_name: "no one", partial_name: "new_submission"}, to: "expertiza@mailinator.com"}
     expect{review_response_map.email(defn, participant, Assignment.find(Participant.find(reviewer_id).parent_id)) }.to change { ActionMailer::Base.deliveries.count }.by (1)
     expect { review_response_map.email(defn, participant, Assignment.find(Participant.find(reviewer_id).parent_id)) }.to change { ActionMailer::Base.deliveries.count }.by (1)
   end
   end
</pre>
</pre>


=== Prepare final review versions ===
=== Prepare final review versions ===
Prepare_final_review_versions method returns the final review versions.
<pre>
<pre>
   def self.prepare_final_review_versions(assignment, maps)
   it '#prepare_final_review_versions' do
     review_final_versions = {}
     review_final_versions = {}
    rounds_num = assignment.rounds_of_reviews
    if rounds_num and rounds_num > 1
      (1..rounds_num).each do |round|
        prepare_review_response(assignment, maps, review_final_versions, round)
      end
    else
      prepare_review_response(assignment, maps, review_final_versions, nil)
    end
    review_final_versions
  end
</pre>
</pre>
Test the prepare_final_review_versions method.
 
When round exists.
<pre>
<pre>
  it '#prepare_final_review_versions' do
    review_final_versions = {}
     reviewer_id = 1
     reviewer_id = 1
     allow(metareview_response_map1).to receive(:id).and_return(1)
     allow(metareview_response_map).to receive(:id).and_return(1)
     allow(Participant).to receive(:find).with(1).and_return(participant)
     allow(Participant).to receive(:find).with(1).and_return(participant)
     allow(Assignment).to receive(:find).with(1).and_return(assignment)
     allow(Assignment).to receive(:find).with(1).and_return(assignment)
     allow(MetareviewResponseMap).to receive(:where).with(reviewed_object_id:1).and_return([metareview_response_map1])
     allow(MetareviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([metareview_response_map])
     allow(Response).to receive(:where).with(map_id: 1, round: 1).and_return([response])
     allow(Response).to receive(:where).with(map_id: 1, round: 1).and_return([response])
     allow(assignment).to receive(:review_questionnaire_id).with(1).and_return(1)
     allow(assignment).to receive(:review_questionnaire_id).with(1).and_return(1)
     allow(Response).to receive(:where).with(map_id: 1, round: 2).and_return([response1])
     allow(Response).to receive(:where).with(map_id: 1, round: 2).and_return([response1])
     allow(assignment).to receive(:review_questionnaire_id).with(2).and_return(1)
     allow(assignment).to receive(:review_questionnaire_id).with(2).and_return(1)
     expect(ReviewResponseMap.prepare_final_review_versions(Assignment.find(Participant.find(reviewer_id).parent_id), MetareviewResponseMap.where(reviewed_object_id: 1))).to eq({"review round1":{questionnaire_id: 1, response_ids:[1]}, "review round2":{questionnaire_id: 1, response_ids:[2] }})
     expect(ReviewResponseMap.prepare_final_review_versions(Assignment.find(Participant.find(reviewer_id).parent_id), MetareviewResponseMap.where(reviewed_object_id: 1))).to eq("review round1": {questionnaire_id: 1, response_ids: [1]}, "review round2": {questionnaire_id: 1, response_ids: [2]})
</pre>
 
When round = nil.
<pre>
     reviewer_id = 2
     reviewer_id = 2
     allow(Participant).to receive(:find).with(2).and_return(participant1)
     allow(Participant).to receive(:find).with(2).and_return(participant1)
     allow(Assignment).to receive(:find).with(2).and_return(assignment1)
     allow(Assignment).to receive(:find).with(2).and_return(assignment1)
     allow(MetareviewResponseMap).to receive(:where).with(reviewed_object_id:1).and_return([metareview_response_map1])
     allow(MetareviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([metareview_response_map])
     allow(assignment).to receive(:review_questionnaire_id).with(nil).and_return(1)
     allow(assignment).to receive(:review_questionnaire_id).with(nil).and_return(1)
     allow(Response).to receive(:where).with(map_id: 1).and_return([response2])
     allow(Response).to receive(:where).with(map_id: 1).and_return([response2])
     expect(ReviewResponseMap.prepare_final_review_versions(Assignment.find(Participant.find(reviewer_id).parent_id), MetareviewResponseMap.where(reviewed_object_id: 1))).to eq({ review:{questionnaire_id: nil, response_ids:[3]}})
     expect(ReviewResponseMap.prepare_final_review_versions(Assignment.find(Participant.find(reviewer_id).parent_id), MetareviewResponseMap.where(reviewed_object_id: 1))).to eq(review: {questionnaire_id: nil, response_ids: [3]})
   end
   end
</pre>
</pre>


=== Prepare review response ===
=== Prepare review response ===
<pre>
Prepare_review_response method returns the response id associated with assignment.
  def self.prepare_review_response(assignment, maps, review_final_versions, round)
    symbol = if round.nil?
              :review
            else
              ("review round" + round.to_s).to_sym
            end
    review_final_versions[symbol] = {}
    review_final_versions[symbol][:questionnaire_id] = assignment.review_questionnaire_id(round)
    response_ids = []
    maps.each do |map|
      where_map = {map_id: map.id}
      where_map[:round] = round unless round.nil?
      responses = Response.where(where_map)
      response_ids << responses.last.id unless responses.empty?
    end
    review_final_versions[symbol][:response_ids] = response_ids
  end
</pre>
Test prepare_review_response method.
<pre>
<pre>
   it '#prepare_review_response' do
   it '#prepare_review_response' do
Line 415: Line 347:
     allow(Assignment).to receive(:find).with(1).and_return(assignment)
     allow(Assignment).to receive(:find).with(1).and_return(assignment)
     allow(Response).to receive(:where).with(map_id: 1, round: 1).and_return([response])
     allow(Response).to receive(:where).with(map_id: 1, round: 1).and_return([response])
    allow(assignment).to receive(:review_questionnaire_id).with(1).and_return(1)
     expect(ReviewResponseMap.prepare_review_response(assignment, maps, review_final_versions, round)).to eq([1])
     expect(ReviewResponseMap.prepare_review_response(assignment, maps, review_final_versions, round)).to eq([1])
     round = nil
     round = nil
     allow(Assignment).to receive(:find).with(1).and_return(assignment)
     allow(Assignment).to receive(:find).with(1).and_return(assignment)
    allow(assignment).to receive(:review_questionnaire_id).with(nil).and_return(1)
     allow(Response).to receive(:where).with(map_id: 1).and_return([response2])
     allow(Response).to receive(:where).with(map_id: 1).and_return([response2])
     expect(ReviewResponseMap.prepare_review_response(assignment, maps, review_final_versions, round)).to eq([3])
     expect(ReviewResponseMap.prepare_review_response(assignment, maps, review_final_versions, round)).to eq([3])
   end
   end
</pre>
</pre>


==Running Rspec==
==Running Rspec==

Latest revision as of 22:09, 9 November 2018

This wiki page is for the description of unit test for E1850 OSS assignment for Fall 2018, CSC/ECE 517.

Background

Expertiza is an open source web based on peer review system developed and maintained by students and faculty members at North Carolina State University. It enables students who enrolled in a particular course to form online teams, complete assignments, review other's work and receive feedbacks of their works.

Problem

Review_response_map.rb is used to prepare data for peer review. But there are no unit tests for it.

Work to be done

  • Create a new file named review_response_map_spec.rb under spec/models folder
  • Write RSpec unit tests to make the path coverage above 90%.
  • Coverage edge cases.
  • Achieve high branch coverage. Use the mutant-rspec gem to measure test thoroughness and fault-finding capability of tests.

Files Created

  • spec/models/review_response_map_spec.rb

Test Plan

Setup expertiza environment

Follow the instruction on http://wiki.expertiza.ncsu.edu/index.php/Development:Setup:OSX#Get_Expertiza

Model functions

To better test the methods, we read the whole review response map model and understand the functionalities of what we want to test.

  • Questionnaire: find the specific questionnaire.
  • Get title: set the title.
  • Delete: delete the feedback response map and metareview response map.
  • Export fields: set the fields of export.
  • Export: export the review response map.
  • Import: import the review response map from local.
  • Show feedback: show the feedback via html.
  • Metareview response maps: fetch all the metareview response map and return.
  • Get responses for team round: get the responses for given round.
  • Final versions from reviewer: return the final review version from reviewers.
  • Review response report: find the reviewers for a given assignment.
  • Email: send an email to the members in a team.
  • Prepare final review versions: prepare the final review versions for an assignment.
  • Prepare review response: return the review responses id for an assignment.

Mock instance

We mock the necessary instances for the test in the beginning of test file.

  let(:team) { build(:assignment_team, id: 1, name: 'team no name', assignment: assignment, users: [student], parent_id: 1) }
  let(:team1) { build(:assignment_team, id: 2, name: 'team has name', assignment: assignment, users: [student]) }
  let(:review_response_map) { build(:review_response_map, id: 1, assignment: assignment, reviewer: participant, reviewee: team, reviewed_object_id: 1) }
  let(:review_response_map1) { build(:review_response_map, id: 2, assignment: assignment, reviewer: participant1, reviewee: team1, reviewed_object_id: 1) }
  let(:feedback) { FeedbackResponseMap.new(id: 1, reviewed_object_id: 1, reviewer_id: 1, reviewee_id: 1) }
  let(:participant) { build(:participant, id: 1, parent_id: 1, user: build(:student, parent_id: 1, name: 'no name', fullname: 'no one')) }
  let(:participant1) { build(:participant, id: 2, parent_id: 2, user: build(:student, parent_id: 1, name: 'has name', fullname: 'has one')) }
  let(:assignment) { build(:assignment, id: 1, name: 'Test Assgt', rounds_of_reviews: 2) }
  let(:assignment1) { build(:assignment, id: 2, name: 'Test Assgt', rounds_of_reviews: 1) }
  let(:response) { build(:response, id: 1, map_id: 1, round: 1, response_map: review_response_map,  is_submitted: true) }
  let(:response1) { build(:response, id: 2, map_id: 1, round: 2, response_map: review_response_map) }
  let(:response2) { build(:response, id: 3, map_id: 1, round: nil, response_map: review_response_map, is_submitted: true) }
  let(:metareview_response_map) { MetareviewResponseMap.new(reviewed_object_id: 1) }
  let(:student) { build(:student, id: 1, fullname: 'no one', email: 'expertiza@mailinator.com') }
  let(:questionnaire) { Questionnaire.new(id: 1, type: 'ReviewQuestionnaire') }
  let(:response_map) { ResponseMap.new(id: 1, reviewed_object_id: 1, reviewee_id: 1, reviewer_id: 1, type: "ReviewResponseMap", response: [response], calibrate_to: 0) }
  let(:user) { User.new(id: 1, name: "name", fullname: 'fullname') }
  let(:user1) { User.new(id: 2, name: "name1", fullname: 'fullname') }
  let(:assignment_participant) { AssignmentParticipant.new(user_id: 1, parent_id: 1) }
  let(:assignment_participant1) { AssignmentParticipant.new(id: 1, user_id: 2, parent_id: 1) }

Implementation

Write test for the methods in review_response_map.rb.

Questionnaire

Questionnaire method returns a questionnaire associated with an assignment.

  it '#questionnaire' do
    round = 1
    allow(assignment).to receive(:review_questionnaire_id).and_return(1)
    allow(Questionnaire).to receive(:find_by).with(id: 1).and_return(questionnaire)
    expect(review_response_map.questionnaire(1)).to eq(questionnaire)
  end

Get title

Get_title method returns the title.

  it '#get_title' do
    expect(review_response_map.get_title).to eq("Review")
  end

Delete

Delete method deletes the feedback_response_map and metareview_response_map and return review_response_map.

  it '#delete' do
    allow(Response).to receive(:find).and_return(response)
    allow(FeedbackResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([feedback])
    allow(MetareviewResponseMap).to receive(:where).and_return([metareview_response_map])
    expect(review_response_map.delete).to equal(review_response_map)
  end

Export fields

Export_fields method which shows the title of export csv file, "contributor" and "reviewed by".

  it '#export_fields' do
    expect(ReviewResponseMap.export_fields(options)).to eq(["contributor", "reviewed by"])
  end

Export

Export method exports the name of reviewer and reviewee and return the map.

  it '#export' do
    csv = []
    parent_id = 1
    options = nil
    allow(ReviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([review_response_map, review_response_map1])
    expect(ReviewResponseMap.export(csv, parent_id, options)).to eq([review_response_map1, review_response_map])
  end

Import

Import method allows user to import the csv file and check it. After that, it returns the name of reviewers.

  it '#import' do
    row_hash = {reviewee: "name", reviewers: ["name1"]}
    session = nil
    assignment_id = 1

When reviewee user = nil

    allow(User).to receive(:find_by).and_return(nil)
    expect { ReviewResponseMap.import(row_hash, session, 1) }.to raise_error(ArgumentError, message = "Cannot find reviewee user.")

When reviewee user exists but reviewee user is not a participant in this assignment.

    allow(User).to receive(:find_by).with(name: "name").and_return(user)
    allow(AssignmentParticipant).to receive(:find_by).with(user_id: 1, parent_id: 1).and_return(nil)
    expect { ReviewResponseMap.import(row_hash, session, 1) }.to raise_error(ArgumentError, message = "Reviewee user is not a participant in this assignment.")

When reviewee user exists and reviewee user is a participant in this assignment.

    allow(AssignmentParticipant).to receive(:find_by).with(user_id: 1, parent_id: 1).and_return(assignment_participant)
    allow(AssignmentTeam).to receive(:team).with(assignment_participant).and_return(team)

When reviewer user doesn't exist.

    allow(User).to receive(:find_by).with(name: "name1").and_return(nil)
    expect { ReviewResponseMap.import(row_hash, session, 1) }.to raise_error(ArgumentError, message = "Cannot find reviewer user.")

When reviewer user exists.

    allow(User).to receive(:find_by).with(name: "name1").and_return(user1)

When reviewer user is not a participant in this assignment.

    allow(AssignmentParticipant).to receive(:find_by).with(user_id: 2, parent_id: 1).and_return(nil)
    expect { ReviewResponseMap.import(row_hash, session, 1) }.to raise_error(ArgumentError, message = "Reviewer user is not a participant in this assignment.")

When reviewer user is a participant in this assignment.

    allow(AssignmentParticipant).to receive(:find_by).with(user_id: 2, parent_id: 1).and_return(assignment_participant1)
    allow(ReviewResponseMap).to receive(:find_or_create_by).with(reviewed_object_id: 1, reviewer_id: 1, reviewee_id: 1, calibrate_to: false).and_return(review_response_map)
    expect(ReviewResponseMap.import(row_hash, session, 1)).to eq(["name1"])

When reviewee_team = nil

    allow(AssignmentTeam).to receive(:team).with(assignment_participant).and_return(nil)
    allow(AssignmentTeam).to receive(:create).and_return(double('team', id: 1))
    allow(TeamsUser).to receive(:create).with(team_id: 1, user_id: 1).and_return(double('teams_users', id: 1, team_id: 1, user_id: 1))
    allow(TeamNode).to receive(:create).with(parent_id: assignment_id, node_object_id: 1).and_return(double('team_node', id: 1, parent_id: 1, node_object_id: 1))
    allow(TeamUserNode).to receive(:create).with(parent_id: 1, node_object_id: 1).and_return(double('team_user_node', id: 1, parent_id: 1, node_object_id: 1))
    allow(User).to receive(:find_by).with(name: "name1").and_return(user1)
    allow(AssignmentParticipant).to receive(:find_by).with(user_id: 2, parent_id: 1).and_return(assignment_participant1)
    allow(ReviewResponseMap).to receive(:find_or_create_by).with(reviewed_object_id: 1, reviewer_id: 1, reviewee_id: 1, calibrate_to: false).and_return(review_response_map)
    expect(ReviewResponseMap.import(row_hash, session, 1)).to eq(["name1"])
  end

Show feedback

Show_feedback method returns the html associated with response.

    it '#show_feedback' do
      allow(review_response_map).to receive(:response).and_return([response])
      allow(Response).to receive(:find).and_return(response)
      allow(FeedbackResponseMap).to receive(:find_by).with(reviewed_object_id: 1).and_return(feedback)
      allow(feedback).to receive(:response).and_return([response])
      expect(review_response_map.show_feedback(response)).to eq("<table width=\"100%\"><tr><td align=\"left\" width=\"70%\"><b>Review </b>"\
          "   <a href=\"#\" name= \"review_1Link\" onClick=\"toggleElement('review_1','review');return false;\">"\
          "show review</a></td><td align=\"left\"><b>Last Reviewed:</b><span>Not available</span></td></tr></table><table id=\"review_1\""\
          " style=\"display: none;\" class=\"table table-bordered\"><tr><td><b>"\
          "Additional Comment: </b></td></tr></table>")
    end

Metareview response maps

Metareview_response_maps method returns metareview_list associated with responses.

  it '#metareview_response_maps' do
    allow(Response).to receive(:where).with(map_id: 1).and_return([response])
    allow(MetareviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([metareview_response_map])
    expect(review_response_map.metareview_response_maps).to eq([metareview_response_map])
  end

Get responses for team round

Get_responses_for_team_round method returns the responses associated with team and round.

  it '#get_responses_for_team_round' do
    allow(Team).to receive(:find).and_return(team)
    round = 1
    allow(ResponseMap).to receive(:where).with(reviewee_id: team.id, type: "ReviewResponseMap").and_return([response_map])
    expect(ReviewResponseMap.get_responses_for_team_round(team, 1)).to eq([response])
  end

Final versions from reviewer

Final_versions_from_reviewer method returns the questionnaire and response ids associated with reviewer.

  it '#final_versions_from_reviewer' do
    reviewer_id = 1
    allow(ReviewResponseMap).to receive(:where).with(reviewer_id: 1).and_return([review_response_map])
    allow(Participant).to receive(:find).with(1).and_return(participant)
    allow(participant).to receive(:parent_id).and_return(1)
    allow(Assignment).to receive(:find).with(1).and_return(assignment)
    allow(Response).to receive(:where).with(map_id: 1, round: 1).and_return([response])
    allow(assignment).to receive(:review_questionnaire_id).with(1).and_return(1)
    allow(Response).to receive(:where).with(map_id: 1, round: 2).and_return([response1])
    allow(assignment).to receive(:review_questionnaire_id).with(2).and_return(1)
    expect(ReviewResponseMap.final_versions_from_reviewer(1)).to eq("review round1": {questionnaire_id: 1, response_ids: [1]}, "review round2": {questionnaire_id: 1, response_ids: [2]})
  end

Review response report

Review_response_report method returns the participants associated with assignment.

  it '#review_response_report' do
    id = 1
    type = "MetareviewResponseMap"
    reviewer_id = 1
    user_ids = []

When review user exists.

    review_user = user
    allow(Participant).to receive(:find).with(1).and_return(participant)
    allow(Assignment).to receive(:find).with(1).and_return(assignment)
    allow(User).to receive_message_chain(:select, :where).and_return([user])
    allow(AssignmentParticipant).to receive(:where).and_return([assignment_participant])
    expect(ReviewResponseMap.review_response_report(id, Assignment.find(Participant.find(reviewer_id).parent_id), type, review_user)).to eq([assignment_participant])

When review user doesn't exists.

    review_user = nil
    allow(ResponseMap).to receive_message_chain(:select, :where).and_return([response_map])
    allow([response_map]).to receive(:reviewer_id).and_return(1)
    allow(AssignmentParticipant).to receive(:find).with(1).and_return([assignment_participant])
    allow(Participant).to receive(:sort_by_name).and_return([assignment_participant])
    expect(ReviewResponseMap.review_response_report(id, Assignment.find(Participant.find(reviewer_id).parent_id), type, review_user)).to eq([assignment_participant])
  end

Email

Email method can successfully send an email.

  it '#email' do
    reviewer_id = 1
    allow(Participant).to receive(:find).with(1).and_return(participant)
    allow(Assignment).to receive(:find).with(1).and_return(assignment)
    allow(AssignmentTeam).to receive(:find).with(1).and_return(team)
    allow(AssignmentTeam).to receive(:users).and_return(student)
    allow(User).to receive(:find).with(1).and_return(student)
    review_response_map.reviewee_id = 1
    defn = {body: {type: "Peer Review", obj_name: "Test Assgt", first_name: "no one", partial_name: "new_submission"}, to: "expertiza@mailinator.com"}
    expect { review_response_map.email(defn, participant, Assignment.find(Participant.find(reviewer_id).parent_id)) }.to change { ActionMailer::Base.deliveries.count }.by (1)
  end

Prepare final review versions

Prepare_final_review_versions method returns the final review versions.

  it '#prepare_final_review_versions' do
    review_final_versions = {}

When round exists.

    reviewer_id = 1
    allow(metareview_response_map).to receive(:id).and_return(1)
    allow(Participant).to receive(:find).with(1).and_return(participant)
    allow(Assignment).to receive(:find).with(1).and_return(assignment)
    allow(MetareviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([metareview_response_map])
    allow(Response).to receive(:where).with(map_id: 1, round: 1).and_return([response])
    allow(assignment).to receive(:review_questionnaire_id).with(1).and_return(1)
    allow(Response).to receive(:where).with(map_id: 1, round: 2).and_return([response1])
    allow(assignment).to receive(:review_questionnaire_id).with(2).and_return(1)
    expect(ReviewResponseMap.prepare_final_review_versions(Assignment.find(Participant.find(reviewer_id).parent_id), MetareviewResponseMap.where(reviewed_object_id: 1))).to eq("review round1": {questionnaire_id: 1, response_ids: [1]}, "review round2": {questionnaire_id: 1, response_ids: [2]})

When round = nil.

    reviewer_id = 2
    allow(Participant).to receive(:find).with(2).and_return(participant1)
    allow(Assignment).to receive(:find).with(2).and_return(assignment1)
    allow(MetareviewResponseMap).to receive(:where).with(reviewed_object_id: 1).and_return([metareview_response_map])
    allow(assignment).to receive(:review_questionnaire_id).with(nil).and_return(1)
    allow(Response).to receive(:where).with(map_id: 1).and_return([response2])
    expect(ReviewResponseMap.prepare_final_review_versions(Assignment.find(Participant.find(reviewer_id).parent_id), MetareviewResponseMap.where(reviewed_object_id: 1))).to eq(review: {questionnaire_id: nil, response_ids: [3]})
  end

Prepare review response

Prepare_review_response method returns the response id associated with assignment.

  it '#prepare_review_response' do
    review_final_versions = {}
    review_response_map.id = 1
    round = 1
    maps = [review_response_map]
    allow(Assignment).to receive(:find).with(1).and_return(assignment)
    allow(Response).to receive(:where).with(map_id: 1, round: 1).and_return([response])
    expect(ReviewResponseMap.prepare_review_response(assignment, maps, review_final_versions, round)).to eq([1])
    round = nil
    allow(Assignment).to receive(:find).with(1).and_return(assignment)
    allow(Response).to receive(:where).with(map_id: 1).and_return([response2])
    expect(ReviewResponseMap.prepare_review_response(assignment, maps, review_final_versions, round)).to eq([3])
  end

Running Rspec

The tests can be run on the terminal from inside the expertiza folder using following commands:

 rspec spec/models/review_response_map_spec.rb

Unit Test Result

app/models/review_response_map.rb
100.0 % covered
102 relevant lines. 102 lines covered and 0 lines missed.

Full video for this test can be found at https://drive.google.com/file/d/18vr3q2dCyh3_tsFLH8w9y6Y9uhdz0Ljj/view?usp=sharing

External Links

https://github.com/Sauve-moi/expertiza