CSC/ECE 517 Fall 2021 - E2132. Add tests cases for review mapping helper.rb

From Expertiza_Wiki
Jump to navigation Jump to search

About Expertiza

Expertiza is the software benefits for both instructors and students by supporting various types of submission and providing reusable objects for peer review. It is an open source project based on Ruby on Rails framework. It allows the instructors not only to create and customize new or existing assignments, but also to create a list of topics the students can sign up for. Students can form teams to work on various projects and assignments. Expertiza also lets students peer review other students' submissions, enables them working together to improve others' learning experience.

Description about project

This page is a description of Expertiza OSS project E2132 which is adding unit tests for review_mapping_helper.rb. The ReviewMappingHelper works as a class that is responsible for mapping reviews and feedback to assignment teams and reviewers. Also, This helper class reports of the status of project reviews.


Files Involved

review_mapping_helper.rb

review_mapping_helper_spec.rb

Running Tests

  rspec ./spec/helpers/review_mapping_helper_spec.rb

Test Plan

In the beginning of the project, we first ran the original test cases and found out two methods were wrong that let the test failed, which are get_team_color and check_submission_state. Therefore, in order to avoid making dramatic and unexpected changes in the original code, we ignored these two methods and started adding test cases in each method in review mapping helper.rb that mentioned below.

Relevant Methods

  • response_for_each_round?
  • submitted_within_round?
  • submitted_hyperlink
  • get_team_reviewed_link_name
  • sort_reviewer_by_review_volume_desc
  • list_review_submission
  • list_hyperlink_submission
  • get_css_style_for_calibration_report

response_for_each_round?

This method returns in boolean function if all required responses are received in each round. For instance, two responses are required in two rounds. It is expected to return true when both responses are received. Otherwise, it returns false if it receives only one or no response.

    it 'should return false if response wasnt submitted in every round' do
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2)

      create(:response, response_map: @response_map)
      check_response = response_for_each_round?(@response_map)
      expect(check_response).to eq(false)
    end

    #one round, one response
    it 'should return true if there is one response with one round' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')

      # make a team for the assignment
      create(:assignment_team, assignment: @assignment)

      response_map_with_reviewee = create(:review_response_map, reviewer: @reviewer, reviewee: @reviewee)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'random link', created_at: DateTime.now.in_time_zone - 7.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 5.day)
      create(:response, response_map: response_map_with_reviewee)

      check_response = response_for_each_round?(response_map_with_reviewee)
      expect(check_response).to eq(true)
    end

    #two round,two response
    it 'should return true if there were both response' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')

      # make a team for the assignment
      create(:assignment_team, assignment: @assignment)

      response_map_with_reviewee = create(:review_response_map, reviewer: @reviewer, reviewee: @reviewee)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'random link', created_at: DateTime.now.in_time_zone - 7.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'random link', created_at: DateTime.now.in_time_zone - 3.day)

      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 5.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone - 2.day)
      create(:response, response_map: response_map_with_reviewee, round: 1)
      create(:response, response_map: response_map_with_reviewee, round: 2)

      check_response = response_for_each_round?(response_map_with_reviewee)
      expect(check_response).to eq(true)
    end

    #two round, only have first response
    it 'should return false if only have first response' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')

      # make a team for the assignment
      create(:assignment_team, assignment: @assignment)

      response_map_with_reviewee = create(:review_response_map, reviewer: @reviewer, reviewee: @reviewee)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'random link', created_at: DateTime.now.in_time_zone - 2.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'random link', created_at: DateTime.now.in_time_zone - 3.day)

      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 5.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone + 6.day)
      create(:response, response_map: response_map_with_reviewee, round: 1)

      check_response = response_for_each_round?(response_map_with_reviewee)
      expect(check_response).to eq(false)
    end

    #two round,only have second response
    it 'should return false if only have second response' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')

      # make a team for the assignment
      create(:assignment_team, assignment: @assignment)

      response_map_with_reviewee = create(:review_response_map, reviewer: @reviewer, reviewee: @reviewee)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'random link', created_at: DateTime.now.in_time_zone - 7.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'random link', created_at: DateTime.now.in_time_zone - 1.day)

      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 5.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone - 2.day)
      create(:response, response_map: response_map_with_reviewee, round: 2)

      check_response = response_for_each_round?(response_map_with_reviewee)
      expect(check_response).to eq(false)
    end

submitted_within_round?

This method checks the record if the assignment is submitted on time, that is, before due date. In the unit test, two submissions on two different due date are set up, and therefore would be four situations to discuss. In the first situation, all the works are submitted on time, the response is expected to be true. In the second situation, both of the works are delayed, so the response definitely returns false. If either one of the submission is delayed, the response depends on the last submission's status. That is, if the last submission is on time, the response is true. On the other hand, if the last submission is delayed, the response is false even thought the former submission is on time.


    it 'should return true if works were submitted within 2 round' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 7.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 1.day)
      create(:response, response_map: @response_map)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 5.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone + 6.day)

      assignment_created = @assignment.created_at
      assignment_due_dates = DueDate.where(parent_id: @response_map.reviewed_object_id)

      check_submitetd = submitted_within_round?(@round, @response_map, assignment_created, assignment_due_dates)
      expect(check_submitetd).to eq(true)
    end

    #for two round, both of the submissions are late
    it 'should return false if both works was submitted late' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 4.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 3.day)
      create(:response, response_map: @response_map)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 10.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone - 5.day)

      assignment_created = @assignment.created_at
      assignment_due_dates = DueDate.where(parent_id: @response_map.reviewed_object_id)

      check_submitetd = submitted_within_round?(@round, @response_map, assignment_created, assignment_due_dates)
      expect(check_submitetd).to eq(false)
    end

    # for two round, only the second submission is on time
    # We spent some time to figure out the logic in this function,
    # but now we believe whether an assignment is late depends on the last due date.
    # So, assignment will view as on time if user submitted before the last deadline.
    it 'should return true if first work was submitted late' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 7.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 6.day)
      create(:response, response_map: @response_map)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 10.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone - 5.day)

      assignment_created = @assignment.created_at
      assignment_due_dates = DueDate.where(parent_id: @response_map.reviewed_object_id)

      check_submitetd = submitted_within_round?(@round, @response_map, assignment_created, assignment_due_dates)
      expect(check_submitetd).to eq(true)
    end

    # for two round, only the first submission is on time
    # If you miss the last submission, than it will return false
    it 'should return false if second work was submitted late' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 11.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 2.day)
      create(:response, response_map: @response_map)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 10.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone - 5.day)

      assignment_created = @assignment.created_at
      assignment_due_dates = DueDate.where(parent_id: @response_map.reviewed_object_id)

      check_submitetd = submitted_within_round?(@round, @response_map, assignment_created, assignment_due_dates)
      expect(check_submitetd).to eq(false)
    end

submitted_hyperlink

This method returns the hyperlink that is submitted on time. For one assignment, it returns the hyperlink that is submitted before due date. For multiple assignments, no matter how many assignments are submitted on time, it shows the hyperlink of the last submission that is submitted on time.

    it 'should return https://wiki.archlinux.org/123 if works was submitted on time' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 12.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/123', created_at: DateTime.now.in_time_zone - 7.day)
      create(:response, response_map: @response_map)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 10.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone - 5.day)

      assignment_created = @assignment.created_at
      assignment_due_dates = DueDate.where(parent_id: @response_map.reviewed_object_id)

      hyper_link = submitted_hyperlink(@round, @response_map, assignment_created, assignment_due_dates)
      expect(hyper_link).to eq('https://wiki.archlinux.org/123')
    end

    it 'should return https://wiki.archlinux.org/123 if only a work was submitted on time' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 8.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/123', created_at: DateTime.now.in_time_zone - 6.day)
      create(:response, response_map: @response_map)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 10.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone - 5.day)

      assignment_created = @assignment.created_at
      assignment_due_dates = DueDate.where(parent_id: @response_map.reviewed_object_id)

      hyper_link = submitted_hyperlink(@round, @response_map, assignment_created, assignment_due_dates)
      expect(hyper_link).to eq('https://wiki.archlinux.org/123')
    end

    it 'should return https://wiki.archlinux.org/ if only a work was submitted on time' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 12.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/123', created_at: DateTime.now.in_time_zone - 4.day)
      create(:response, response_map: @response_map)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 10.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone - 5.day)

      assignment_created = @assignment.created_at
      assignment_due_dates = DueDate.where(parent_id: @response_map.reviewed_object_id)

      hyper_link = submitted_hyperlink(@round, @response_map, assignment_created, assignment_due_dates)
      expect(hyper_link).to eq('https://wiki.archlinux.org/')
    end


    it 'should return https://wiki.archlinux.org/ if only a work was Submit Hyperlink' do
      create(:deadline_right, name: 'No')
      create(:deadline_right, name: 'Late')
      create(:deadline_right, name: 'OK')
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Submit Hyperlink', content: 'https://wiki.archlinux.org/', created_at: DateTime.now.in_time_zone - 12.day)
      create(:submission_record, assignment_id: @assignment.id, team_id: @reviewee.id, operation: 'Not Submit Hyperlink', content: 'https://wiki.archlinux.org/123', created_at: DateTime.now.in_time_zone - 6.day)
      create(:response, response_map: @response_map)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 1, due_at: DateTime.now.in_time_zone - 10.day)
      create(:assignment_due_date, assignment: @assignment, parent_id: @assignment.id, round: 2, due_at: DateTime.now.in_time_zone - 5.day)

      assignment_created = @assignment.created_at
      assignment_due_dates = DueDate.where(parent_id: @response_map.reviewed_object_id)

      hyper_link = submitted_hyperlink(@round, @response_map, assignment_created, assignment_due_dates)
      expect(hyper_link).to eq('https://wiki.archlinux.org/')
    end

get_team_reviewed_link_name

This method returns appropriate team name for assignments. For assignments with 1 team member, the following method returns user's full name. Otherwise, it returns "team name" that a particular reviewee belongs to.

    it 'should return (Team_1) if max_team_size = 3' do
      max_team_size = 3
      @response = create(:response, response_map: @response_map)
      ip_address = '0.0.0.0'
      reviewed_team_name = get_team_reviewed_link_name(max_team_size, @response, @reviewee.id, ip_address)
      expect(reviewed_team_name).to eq('(Team_1)')
    end

    it 'should return (Team_1) if max_team_size = 2' do
      max_team_size = 2
      @response = create(:response, response_map: @response_map)
      ip_address = '0.0.0.0'
      reviewed_team_name = get_team_reviewed_link_name(max_team_size, @response, @reviewee.id, ip_address)
      expect(reviewed_team_name).to eq('(Team_1)')
    end

    it 'should return (Adam) if max_team_size = 1' do
      max_team_size = 1
      student = create(:student, fullname: 'Adam')
      create(:team_user, user: student, team: @reviewee)

      @response = create(:response, response_map: @response_map)
      ip_address = '0.0.0.0'
      reviewed_team_name = get_team_reviewed_link_name(max_team_size, @response, @reviewee.id, ip_address)
      expect(reviewed_team_name).to eq('(Adam)')
    end

    it 'should return (Team_1) if max_team_size = 0' do
      max_team_size = 0
      @response = create(:response, response_map: @response_map)
      ip_address = '0.0.0.0'
      reviewed_team_name = get_team_reviewed_link_name(max_team_size, @response, @reviewee.id, ip_address)
      expect(reviewed_team_name).to eq('(Team_1)')
    end

sort_reviewer_by_review_volume_desc

This method sorts the reviewer depending on the length of the content of the review. It is sorted in descent order, and follows the order of create if the length of the reviews are the same. In the first test, the length of comment following in the descent order is 2 > 3 > 1, therefore, it returns in the array[@reviewer_2, @reviewer_3, @reviewer_1]. In the second test, since @response_1 has the same length of comment with @response_3 and @response_1 is followed by @response_3, this method returns the array[@reviewer_2, @reviewer_1, @reviewer_3].

it 'the order should be 2-3-1 if the order of comment volume is 2 > 3 > 1' do
      @response_1 = create(:response, response_map: @response_map_1, additional_comment: 'good')
      @response_2 = create(:response, response_map: @response_map_2, additional_comment: 'Good job with clear code')
      @response_3 = create(:response, response_map: @response_map_3, additional_comment: 'goodclear code')

      @reviewers = Array[@reviewer_1, @reviewer_2, @reviewer_3]
      @reviewers_for_test = Array[@reviewer_2, @reviewer_3, @reviewer_1]

      sort_reviewer_by_review_volume_desc
      expect(@reviewers).to eq(@reviewers_for_test)
    end

    it 'the order should be 2-1-3 if the comment volume is 2 > 1 = 3' do
      @response_1 = create(:response, response_map: @response_map_1, additional_comment: 'good job')
      @response_2 = create(:response, response_map: @response_map_2, additional_comment: 'Good job with clear code')
      @response_3 = create(:response, response_map: @response_map_3, additional_comment: 'clear code')

      @reviewers = Array[@reviewer_1, @reviewer_2, @reviewer_3]
      @reviewers_for_test = Array[@reviewer_2, @reviewer_1, @reviewer_3]

      sort_reviewer_by_review_volume_desc
      expect(@reviewers).to eq(@reviewers_for_test)
    end

    it 'the order should be 1-2-3 if the comment volume is 1 = 2 = 3' do
      @response_1 = create(:response, response_map: @response_map_1, additional_comment: 'good job')
      @response_2 = create(:response, response_map: @response_map_2, additional_comment: 'clear code')
      @response_3 = create(:response, response_map: @response_map_3, additional_comment: 'nice bro')

      @reviewers = Array[@reviewer_1, @reviewer_2, @reviewer_3]
      @reviewers_for_test = Array[@reviewer_1, @reviewer_2, @reviewer_3]

      sort_reviewer_by_review_volume_desc
      expect(@reviewers).to eq(@reviewers_for_test)
    end

list_review_submission

This method returns the correct html tag if a review file exist. Otherwise, it should return an empty string when the file does not exist. In the first test, a sudo file created in AssignmentTeam is allowed to find and return a correct html that start with "<a href". In the second test, since the file does not exist, it returns an empty string.

    it 'should return correct html a tag' do
      result = helper.list_review_submissions(@participant.id, @team.id, @response_map.id)
      expect(result).to start_with("<a href")
    end
    it 'should return an empty string when the file does not exist' do
      result = helper.list_review_submissions(@participant.id, @team.id, @response_map.id)
    expect(result).to eq('')

list_hyperlink_submission

This method returns the hyperlink that the student submits. In this unit test, if the submission can be found, the result is expected to be a hyperlink start with '<a target="_blank"'; otherwise, if the student does not submit a response, which means the comment does not exist, an empty string is expected to return.

    it 'should return correct html a tag' do
      result = helper.list_hyperlink_submission(@response_map.id, @question.id)
      expect(result).to start_with('<a target="_blank"')
    end

    it 'should return an empty string when comment does not exist' do
      result = helper.list_hyperlink_submission(@response_map.id, @question.id)
      expect(result).to eq('')
    end 

get_css_style_for_calibration_report

The method transfers the variable diff, the difference between the student's and the instructor's answer into css style. A dictionary is created as dict = {0 => 'c5',1 => 'c4',2 => 'c3',3 => 'c2'}. In the first unit test, "0" set as the the diff is expected to return c5. In the second test, "-1" is a negative integer, so the absolute value is used to return c4. In the third test, since "6" is not in the key of dict, according to the function, it should return c1.

    it 'should return correct css class' do
      css_class_0 = helper.get_css_style_for_calibration_report(0)
      css_class_1 = helper.get_css_style_for_calibration_report(-1)
      css_class_6 = helper.get_css_style_for_calibration_report(6)
      expect(css_class_0). to eq('c5')
      expect(css_class_1). to eq('c4')
      expect(css_class_6). to eq('c1')
    end

Results

59 out of 61 tests in the review_mapping_helper_spec.rb test file. The pull request cannot pass because two of the whole methods in review mapping helper.rb were failed originally. The test cases we created were successfully passed, and the coverage is also increased from 54.04% to 73.74%.

Our code changes can be viewed here.

URL link of video of review_mapping_helper_spec.rb tests running and passing:- here

Collaborators

Chen-Ni Liu (cliu43) / Shao-Yo Chao (schao2) / Fu-Jen Yen (fyen)

Relevant Links

Main Expertiza Repository can be found here.

Our forked Repository can be found here.