CSC/ECE 517 Spring 2019 - Project E1921. Write tests for popup controller.rb

From Expertiza_Wiki
Jump to navigation Jump to search

The goal of this project was to add testing for the PopupController to raise statement coverage above 90%. See the Test Outline section for specifics of our work.

Project Introduction

The PopupController is responsible for preparing data that will be displayed in popup views. To render the data, which mostly concerns assignments, the controller makes many accesses to database tables such as Response, ResponseMap, Question, Questionnaire, Answer, and Participant. Before our project, there were only two tests implemented that together only achieved a statement coverage of 7%. Our changes have brought the statement coverage to 96%.

Team

Zhewei Hu, zhu6 (mentor)

  • Yuhan Chen, ychen239
  • Hao Lu, hlu6
  • Drew Marshburn, rdmarshb

Files Involved

popup_controller.rb

popup_controller_spec.rb

Running Tests

What we need to do is to set up the environment and complete the 'popup_controller_spec.rb' to finish the integration tests for popup controller. This rspec test file can be run by calling the following code:

  rspec spec/controllers/popup_controller_spec.rb

What needs to be done

1.Write RSpec integration tests to make the statement coverage above 90%.

2.Cover as many edge cases as you can.

3.Achieve as high branch coverage as you can. Teaching staff will use the mutant-rspec gem to measure test thoroughness and fault-finding capability of tests.

Test Plan

In total, we wrote tests to cover all 10 methods in the popup controller. We mocked many different objects involved in the controller.

Popup Controller Methods

The code of the controller can be found here. The methods are:

  • action_allowed?
  • author_feedback_popup
  • team_users_popup
  • participants_popup
  • tone_analysis_chart_popup
  • view_review_scores_popup
  • build_tone_analysis_report
  • build_tone_analysis_heatmap
  • reviewer_details_popup
  • self_review_popup

Mock Models

Based on the controller, we mocked models to test different conditions. Models have complex and interdependent relationships, but the Expertiza project already includes a factory to build many of the models. This factory can be seen here. Additional database information can be accessed here. As you can see from our setup below, most of the objects we created relied on the factory with the exception of the final_versions array, which is not used in enough tests to warrant its own factory statement. Other objects are just built with additional/overwritten attributes, such as the student object.

let(:assignment_team) { build(:assignment_team, id: 1, name: "team1", assignment: assignment) }
  let(:team) {build(:team)}
  let(:team_user) {build(:team_user)}
  let(:student) { build(:student, id: 1, name: "student") }
  let(:student2) { build(:student, id: 2, name: "student2") }
  let(:admin) { build(:admin) }
  let(:instructor) { build(:instructor) }
  let(:ta) { build(:teaching_assistant) }
  let(:participant) { build(:participant, id: 1, user_id: 1, user: student, assignment: assignment) }
  let(:participant2) { build(:participant, id: 2, user: student2, assignment: assignment) }

  let(:response) { build(:response, id: 1) }
  let(:questionnaire) { build(:questionnaire, id: 1, max_question_score: 15)}
  let(:question) { build(:question, id: 1, questionnaire_id: questionnaire.id)}
  let(:answer) { build(:answer, id: 1, question_id: question.id, response_id: response.id, answer: 10) }

  let(:assignment) { build(:assignment, id: 1) }
  let(:response_map) { build(:review_response_map, id: 1, reviewee_id: assignment_team.id, reviewer_id: participant2.id, response: [response], assignment: assignment) }
  let(:final_versions) {{
      review_round_one: {questionnaire_id: 1, response_ids: [1]},
      review_round_two: {questionnaire_id: 2, response_ids: [2]},
      review_round_three: {questionnaire_id: 3, response_ids: [3], }
  }}

  test_url = "http://peerlogic.csc.ncsu.edu/reviewsentiment/viz/478-5hf542"
  mocked_comments_one = OpenStruct.new(comments: "test comment")

We made one change to the factory.rb file to build an instance of Team. We assume that the Team class may be used in other tests globally, so this should be added to the factory file and thus can be built more easily in future tests. Our addition to the factory.rb file is:

factory :team, class: Team do
  id 1
  parent_id 1
end

Test Frame

Since it's integration test, we need to test basic logic and return value in both methods in the controller and related methods in the controller. However, some of the methods have been tested in other rspec, all we need to do is to test the methods that haven't been tested. For 'action_allowed?', 'author_feedback_popup', 'team_users_popup', 'participants_popup', 'reviewer_details_popup', 'self_review_popup' methods, we test it separately. With 'tone_analysis_chart_popup', 'view_review_scores_popup', 'build_tone_analysis_report', 'build_tone_analysis_heatmap', we test them together since they both need to get each assignment'answer. Also 'tone_analysis_chart_popup' and 'view_review_scores_popup' all get 'build_tone_analysis_report' and 'build_tone_analysis_heatmap' in their method.

Test Outline

The following section shows the Rspec outline of the tests we created. The full test code can be found here

PopupController

Check action permission with four different roles.

     #action_allowed?
       when the role current user is student
         does not allow certain action
       when the role current user is ta
         allows certain action
       when the role name of current user is super admin or admin
         allows certain action
       when the role current user is super instructor
         allows certain action

Get feedback when feedback exists.

    #author_feedback_popup
      when response_id exists
        get the result

Get response stats when the response map exists, otherwise only find the team and users.

    #team_users_popup
      when a response map exists
        calculates response stats for one response
      when a response map does not exist
        finds team and users

Calculate scores depending on the existence of the response. If a review questionnaire is present, calculate scores with a max.

    #participants_popup
      called with no response
        does not calculate scores
      called with a response
        assignment has a review questionnaire
          calculates the scores with a max
        assignment has no review questionnaire
          calculates the scores without a max

All tone analysis tests are run together. Both popup_* methods set instance variables before calling a build_* method. build_* methods are responsible for actually creating tone analysis tests and returning JSON information/graphics.

    tone analysis tests
      #tone_analysis_chart_popup
        review tone analysis is calculated
          prepares tone analysis report for building
      #view_review_scores_popup
        review tone analysis is calculated
          prepares tone analysis report for building
      #build_tone_analysis_report
        answer is provided
          build tone analysis report
        answer is not provided
          build tone analysis report
      #build_tone_analysis_heatmap
        sentiment is empty
          build tone analysis heatmap

Test showing details about the reviewer.

 
    #reviewer_details_popup
      it will show the reviewer details
        it will show the reviewer details

Get reviews done by self.

  
    #self_review_popup
      when response_id exists
        get the result

Results

The total coverage of the test is 96.41%, meeting our coverage requirement.

Related Links

A video of all tests running can be seen here.

The main repository can be found here

The forked git repository for this project can be found here

Conclusion

The testing framework in the assignment_team_spec.rb used integration tests to test the methods in the controller. The mock instances are created at the beginning and the method logic is tested in each 'describe'. In addition, we used the Byebug gem to debug our test code. The key to building successful tests is to understand the logic in the method and understand the input and output value for the method.