CSC/ECE 517 Spring 2022 - E2201: Testing for assignment questionnaire controller.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 submissions 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, enabling them to work together to improve others' learning experiences.

Current Project Description

This Expertiza OSS project "E2201: Testing for assignment_questionnaire_controller" is focused on adding unit tests for assignment_questionnaire_controller.rb.

Files Involved

  • assignment_questionnaire_controller.rb
  • assignment_questionnaire_controller_spec.rb

Running Tests

  rspec ./spec/controllers/assignment_questionnaire_controller_spec.rb

Test Plan

assignment_questionnaire_controller had 3 methods for which unit tests were missing. The RSpec unit tests added for these methods in the spec file 'assignment_questionnaire_controller_spec.rb' are discussed below.

Assignment Questionnaire Controller Methods

The code of the controller can be found here The methods which miss test cases are:

  • action_allowed?
  • delete_all
  • create

Test Code

action_allowed?

This method checks if a particular action is allowed when it is called for the Assignment. The action is passed in the params. For the controller tested, there were 4 contexts to test. The first being when there is not an assignment associated with the assignment id, the action should not be allowed and returns false. Next, a stub instructor was created to verify if the action would also be false for when an instructor of the assignment was the current user. Similarly this was done for finding if the user was the ancestor of the assignment and this would return true. And again this was done for the case if the assignment's course's ta is the same ta who signed in.

Code snippet:

    context 'when no assignment is associated with the id' do
      #If there is no assignment ID passed, the action should not be allowed. 
      it 'refuses further actions' do
        allow(Assignment).to receive(:find).and_return(nil)
        expect(controller.send(:action_allowed?)).to be_falsey
      end
    end
    context 'instructor is not the instructor of the assignment found' do
      #If the instructor is not an instructor of the assignment found then the instructor mustn't be allowed to perform action
      it 'does not allow instructor to perform action wrt the assignment' do
        stub_current_user(instructor1, instructor1.role.name, instructor1.role)
        allow(Assignment).to receive(:find).and_return(assignment)
        allow_any_instance_of(Assignment).to receive(:instructor).and_return(instructor1)
        expect(controller.send(:action_allowed?)).to be_falsey
      end
    end
    context 'instructor is the instructor for the assignment found' do
      ## If no questionnaire is associated with the id in database, then appropriate missing record error should be flashed
      it 'allows instructor to perform action wrt the assignment' do
        stub_current_user(instructor1, instructor1.role.name, instructor1.role)
        allow(Assignment).to receive(:find).and_return(assignment1)
        allow_any_instance_of(Assignment).to receive(:instructor).and_return(instructor1)
        expect(controller.send(:action_allowed?)).to be_truthy
      end
    end
    context 'user is the ancestor of the assignment found' do
      ##If the user is the ancestor of the instructor who created the course then this user allowed to perform the action. 
      it 'allows user to perform action wrt the assignment' do
        stub_current_user(super_admin, super_admin.role.name, super_admin.role)
        allow(Assignment).to receive(:find).and_return(assignment1)
        allow_any_instance_of(Assignment).to receive(:instructor).and_return(instructor1)
        expect(controller.send(:action_allowed?)).to be_truthy
      end
    end
    context 'TA who is not course TA is not allowed to perform actions on the assignment found' do
      ##If the user is assignment's course's TA, then the user is allowed to perform action wrt assignment.
      it 'does not allow TA to perform action wrt the assignment' do
        course2 = create(:course)
        assignment2 = create(:assignment, course_id: course2.id, instructor_id: instructor1)
        ta1 = create(:teaching_assistant, id: 20)
        ta2 = create(:teaching_assistant, id:40, name: 'test_ta_2')
        TaMapping.create(ta_id: ta1.id, course_id: course2.id)
        
        stub_current_user(ta2, ta2.role.name, ta2.role)
        allow(Assignment).to receive(:find).and_return(assignment2)
        expect(controller.send(:action_allowed?)).to be false
      end
    end

delete_all

This action is called in the process of deleting an assignment_questionnaire that is associated with an assignment. When this action is successfully executed or the questionnaire is successfully destroyed upon an assignment's deletion, then the test below tests to see that the AssignmentQuestionnaire table is updated to reflect this deletion. Furthermore, the tests below verify that an error flash is present if there is no such assignment_id associated with the requested assignment to be deleted.

Code snippet:

   context 'when no assignment is associated with the id in the database' do
      ##If there is no assignment associated with the id in the database then controller must throw an error
      it 'throws an error that the assignment does not exist' do
        stub_current_user(super_admin, super_admin.role.name, super_admin.role)

        allow(Assignment).to receive(:find).with(20).and_return(nil)
        allow(controller).to receive(:params).and_return({ assignment_id: 20})
        controller.send(:delete_all)
        expect(flash[:error]).to be_eql('Assignment #20 does not currently exist.')
      end
    end
  

    # context 'when questionnaires related to an assignment are deleted' do
    #   #When all the questionnaires related to an assignment are deleted the count of assignment_questionnaire records should be 0 for that assignment
    #   it 'should persist that delete in the database' do
    #     assignment3 = create(:assignment)

    #     questionnaire1 = create(:questionnaire)
    #     questionnaire2 = create(:questionnaire)
    #     questionnaire3 = create(:questionnaire)

    #     assignment_questionnaire1 = create(:assignment_questionnaire, assignment_id: assignment3.id, questionnaire_id: questionnaire1.id)
    #     assignment_questionnaire2 = create(:assignment_questionnaire, assignment_id: assignment3.id, questionnaire_id: questionnaire2.id)
    #     assignment_questionnaire3 = create(:assignment_questionnaire, assignment_id: assignment3.id, questionnaire_id: questionnaire3.id)

    #     allow(Assignment).to receive(:find).and_return(assignment3)
    #     allow(controller).to receive(:params).and_return({assignment_id: assignment3.id})
    #     controller.send(:delete_all)

    #     expect(AssignmentQuestionnaire.where(assignment_id: assignment3.id).count).to eq(0)

    #   end
    # end

create

This method is used to create an AssignmentQuestionnaire entry. But first, the testing file below verifies that there is not a missing assignment id when creating an entry. This testing confirmed that the assignment_questionnaire_controller.rb file needed to be updated to remove a portion of the proposed error flash that was unable to convert a nil value to a string in the case of a missing assignment_id. This was the same result for in the case of a missing questionnaire_id.

Code snippet:

  context 'when assignment id is entered as nil' do
        ## If assignment id is nil, then appropriate missing assignment id error should be flashed. 
        it 'flashes a response of missing assignment id' do
          params = {  assignment_id: nil}

          stub_current_user(super_admin, super_admin.role.name, super_admin.role)
          allow(Assignment).to receive(:find).and_return(nil)      
          allow(controller).to receive(:params).and_return(params)
          controller.send(:create)
          expect(flash[:error]).to be_eql('Missing assignment ID - Assignment ID entered is Nil')
        end
      end

      context 'when questionnaire id is entered as nil' do
        ## If questionnaire id is nil, then appropriate missing questionnaire id error should be flashed. 
        it 'flashes a response of missing questionnaire id' do
          params = {  assignment_id: 1, questionnaire_id: nil }

          stub_current_user(super_admin, super_admin.role.name, super_admin.role)
          allow(Assignment).to receive(:find).and_return(assignment)
          allow(Questionnaire).to receive(:find).and_return(nil)
          allow(controller).to receive(:params).and_return(params)
          controller.send(:create)
          expect(flash[:error]).to be_eql('Missing questionnaire ID - Questionnaire ID entered is Nil')
        end
      end
      
      context 'when no assignment is associated with the id in the database' do
        ## If no assignment is associated with the id in database, then appropriate missing record error should be flashed
        it 'throws an error that the assignment does not exist in the db' do
          questionnaire1 = create(:questionnaire)
          params = {  assignment_id: 7, questionnaire_id: questionnaire1.id}
          
          stub_current_user(super_admin, super_admin.role.name, super_admin.role)
          allow(Assignment).to receive(:find).with(7).and_return(nil)
          allow(Questionnaire).to receive(:find).and_return(questionnaire1)
          allow(controller).to receive(:params).and_return(params)
          controller.send(:create)
          expect(flash[:error]).to be_eql('Assignment #7 does not currently exist.')
        end
      end

      context 'when no questionnaire is associated with the id in the database' do
         ## If no questionnaire is associated with the id in database, then appropriate missing record error should be flashed
        it 'throws an error that the questionnaire does not exist in the db' do
          params = { assignment_id: assignment.id, questionnaire_id: 7}
          
          stub_current_user(super_admin, super_admin.role.name, super_admin.role)
          allow(Assignment).to receive(:find).and_return(assignment)
          allow(Questionnaire).to receive(:find).with(7).and_return(nil)
          allow(controller).to receive(:params).and_return(params)
          controller.send(:create)
          
          expect(flash[:error]).to be_eql('Questionnaire #7 does not currently exist.')
        end
      end

      # context 'when saving a new assignment questionnaire' do
      #   ## Checking if the assignment question is saved correctly to the database. 
      #   it 'should save and redirect appropriatley' do
      #     assignment5 = create(:assignment)
      #     questionnaire1 = create(:questionnaire)
      #     params = { assignment_id: assignment5.id, questionnaire_id: questionnaire1.id }

      #     stub_current_user(super_admin, super_admin.role.name, super_admin.role)
      #     allow(Assignment).to receive(:find).and_return(assignment5)
      #     allow(Questionnaire).to receive(:find).and_return(questionnaire1)
      #     allow(controller).to receive(:params).and_return(params)
      #     controller.send(:create)

      #     expect(AssignmentQuestionnaire.where(assignment_id: assignment5.id).count).to eq(1)
      #   end
      # end

Conclusion

The assignment_questionnaire_controller has been thoroughly tested to be merged with expertiza by the use of 12 different contexts as described in detail throughout this wiki page. Building this controller and respective rspec tests using Travis CI in the pull request fails due to a mimemagic error that is currently being resolved by expertiza leadership and does not reflect performance of the assignment_questionnaire rspec testing. There were several errors found and reported for the assignment_questionnaire controller that the team made a point to resolve. An error was found in the controller to include a flash message for both the case of a missing assignment_id and missing questionnaire_id where a nil value was attempting to be converted to a string. To solve this, the team changed the flash message to not include a nil.to_s value and instead implemented a pure string. Next, there were errors in the controller to which .id methods were being called on non-existing objects. To solve this, through testing results, the team passed params[:id].to_s instead for several cases throughout the controller. Additionally, there were several errors related to rendering the assignment_questionnaire paths. It was mentioned that the views associated with the rendering paths may be made with javascript at a later time, so the team chose to test the all the other parts of the controller except for the rendering portions of delete_all and create. However, the test cases for both the delete_all and create method's rendering portion were made and simply commented out for when the expertiza leadership decides which rendering format would benefit expertiza the most. Our goal for this project was to produce controller improving tests and update the controller so that it can be merged with the total system and make the total system perform better.

Related Links

The main repository can be found here.

The forked git repository for this project can be found here.

A video of all tests running can be seen here.