OSS E1852.rb: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
Line 154: Line 154:


<pre>
<pre>
  describe '#delete' do
    describe '#delete' do
     it 'deletes a participant if no associations exist and force is nil' do
     it 'deletes a participant if no associations exist and force is nil' do
       expect(participant.delete(nil)).to eq(participant)
       expect(participant.delete(nil)).to eq(participant)
Line 212: Line 212:
*''scores'' : Returns a hash of values that are applicable to a participant's assignment scores (i.e. { participant information, assignment question information, total scores })
*''scores'' : Returns a hash of values that are applicable to a participant's assignment scores (i.e. { participant information, assignment question information, total scores })
:- how?
:- how?
<pre></pre>
<pre> describe '#score' do
    it 'Get participant score within a round' do
      questions = {:review=>[question1],:review1=> [question]}
      test = [questionnaire,questionnaire1]
 
      allow(participant.assignment).to receive(:questionnaires).and_return(test)
      assessment=double("review")
     
      test.each do |q|
        assignment_questionnaire_map=double("assignment_questionnaire",:used_in_round=>nil)
        if q.id==2
          assignment_questionnaire_map=double("assignment_questionnaire",:used_in_round=>1)
        end
        allow(AssignmentQuestionnaire).to receive(:find_by).with(assignment_id: 1, questionnaire_id: q.id).and_return(assignment_questionnaire_map)
        assessment=double("review")
        allow(q).to receive(:get_assessments_for).with(participant).and_return(assessment)
allow(Answer).to receive(:compute_scores).with(assessment,questions[:review]).and_return(5)
allow(Answer).to receive(:compute_scores).with(assessment,questions[:review1]).and_return(6)
      end
     
      allow(participant.assignment).to receive(:compute_total_score).with(any_args).and_return(75)
      check = participant.scores(questions)
     
      expect(check).to include(:participant => participant)
      expect(check[:review1].to_s).to include({:assessments=> assessment,:scores=>6}.to_s)
      expect(check[:review].to_s).to eq({:assessments=>assessment,:scores=>5}.to_s)
      expect(check).to include(:total_score => 75)
    end
  end</pre>
*''get_permissions'' : Returns the permissions association with a participant based on participant type (i.e. participant, reader, reviewer, submitter).
*''get_permissions'' : Returns the permissions association with a participant based on participant type (i.e. participant, reader, reviewer, submitter).
<pre>
<pre>
Line 237: Line 265:
<pre>
<pre>
   describe '#get_authorization' do
   describe '#get_authorization' do
     it 'returns participant when no arguments are pasted' do
     it 'returns participant when no arguments are passed' do
       expect(Participant.get_authorization(nil, nil, nil)).to eq('participant')
       expect(Participant.get_authorization(nil, nil, nil)).to eq('participant')
     end
     end
     it 'returns reader when no arguments are pasted' do
     it 'returns reader when no arguments are passed' do
       expect(Participant.get_authorization(false, true, true)).to eq('reader')
       expect(Participant.get_authorization(false, true, true)).to eq('reader')
     end
     end
     it 'returns submitter when no arguments are pasted' do
     it 'returns submitter when no arguments are passed' do
       expect(Participant.get_authorization(true, false, false)).to eq('submitter')
       expect(Participant.get_authorization(true, false, false)).to eq('submitter')
     end
     end
     it 'returns reviewer when no arguments are pasted' do
     it 'returns reviewer when no arguments are passed' do
       expect(Participant.get_authorization(false, true, false)).to eq('reviewer')
       expect(Participant.get_authorization(false, true, false)).to eq('reviewer')
     end
     end

Revision as of 20:41, 31 October 2018

This wiki page is for the description of changes made under E1852 OSS assignment for Fall 2018, CSC/ECE 517

Background

Expertiza is an open source web-based peer review system developed and maintained by students and faculty members at North Carolina State University. Features of Expertiza enable students to work collaboratively in teams on course projects and assignments.

Problem

There are not enough unit tests for the Participant model of Expertiza. Current path coverage of participant.rb is only 36.08%.

Work to be done

  • Write unit tests using Rspec
  • Achieve a path coverage of more than 90%
  • Achieve a high branch coverage

Modified Files

  • spec/models/particpant_spec.rb

Unit Test Description

Unit Tests are implemented to ensure proper independence and desired functionality of methods in a model. Unit Testing is an essential component for the following strategies:

  • Test Driven Development(TDD), where unit tests are used to drive the development of a product.
  • Behavior Driven Development(BDD), which augments test driven development through the application of principles such as "Five Why's" and "Outside In" to identify and implement behaviors that are directly beneficial to the outcome of the product.

In this project, RSpec testing models were used to satisfy the testing requirements of behavior driven development.

Participant Unit Test

Factories

We created participant factory since default participant was getting type as "AssignmentParticipant".The following variables were generated using the factory to assist in the testing of the Participant model.

##particpant factory##
    factory: participantSuper, class: Participant do
    can_submit true
    can_review true
    assignment { Assignment.first || association(:assignment) }
    association :user, factory: :student
    submitted_at nil
    permission_granted nil
    penalty_accumulated 0
    grade nil
    handle "handle"
    time_stamp nil
    digital_signature nil
    duty nil
    can_take_quiz true
  end
##Varibales##
let(:user1) { 
	build(:student, id: 1, name: 'no name', fullname: 'no one')}
  let(:team) {	
	build(:assignment_team, id: 1, name: 'myTeam')}
  let(:team_user) { 
	build(:team_user, id: 1, user: user2, team: team)}
  
  let(:user2) { 
	build(:student, id: 4, name: 'no name', fullname: 'no two')}
 
  let(:topic){build(:topic)}
  
  let(:participant) {
	build(:participant,
	user: build(:student, name: "Jane", fullname: "Doe, Jane", id: 1))}
  let(:participant2) { 
	build(:participant, 
	user: build( :student, name: "John", fullname: "Doe, John", id: 2))}
  let(:participant3) { 
	build(:participant, can_review: false, 
	user: build(:student, name: "King", fullname: "Titan, King", id: 3))}
  let(:participant4) { 
	build(:participantSuper, can_review: false, user: user2)}
  
  let(:assignment) {build(:assignment, id: 1, name: 'no assgt')}
  let(:review_response_map) {
	build( :review_response_map, assignment: assignment, reviewer: participant, reviewee: team ) }
  let(:response) {
	build(:response, id: 1, map_id: 1, response_map: review_response_map, scores: [ answer ] ) }
  let( :answer ) { 
	Answer.new( answer: 1, comments: 'Answer text', question_id: 1 ) }
  
  let( :question ) { 
	Criterion.new(id: 1, weight: 2, break_before: true ) }
 let( :question1 ) {
        Criterion.new(id: 2, weight: 2, break_before: true ) }
  let( :questionnaire ) { 
	ReviewQuestionnaire.new(id: 1, questions: [ question ], max_question_score: 5) }
   let( :questionnaire1 ) {
        ReviewQuestionnaire.new(id: 2, questions: [question1], max_question_score: 5) }
  after(:each) do
    ActionMailer::Base.deliveries.clear
  end

Tested Methods

  • team : Returns the team associated with a participant.
- mock simulates the find_by method in TeamsUser object and returns team_user
describe '#team' do
    it 'returns the team of the participant' do
      allow(TeamsUser).to receive(:find_by).and_return(team_user)
      expect( participant4.team ).to eq(team)
    end
  end
  • response : Returns the response associated with a participant.
- mock used to simulate the return of a response from the participant's response_map
  describe '#response' do
    it 'Returns the participant responses' do
      allow(participant.response_maps).to receive(:map).and_return(response)
      expect(participant.responses).to eq(response)
    end
  end
  • name : Returns the name of a participant.
  describe "#name" do
    it "returns the name of the user" do
      expect(participant.name).to eq("Jane")
    end
  end
  • fullname : Returns the full name of a participant.
  describe "#fullname" do
    it "returns the full name of the user" do
      expect(participant.fullname).to eq("Doe, Jane")
    end
  end
  • handle : Returns the handle of a participant.
  describe '#handle' do
    it 'returns the handle of the participant' do
      expect(participant.handle(nil)).to eq("handle")
    end
  end
  • delete : Deletes a participant according to the participant's current associations and the value passed to the variable 'force'.
- mock to simulate the return of the participant team when asked
- mock used in the testing of a forceful delete of a participant with a team association consisting of a single team user by simulating the return of team length to be one when asked
    describe '#delete' do
    it 'deletes a participant if no associations exist and force is nil' do
      expect(participant.delete(nil)).to eq(participant)
    end
    it 'deletes a participant if no associations exist and force is true' do
      expect(participant.delete(true)).to eq(participant)
    end
    it 'delete a participant with associations and force is true and multiple team_users' do
      allow(participant).to receive(:team).and_return(team)
      expect(participant.delete(true)).to eq(participant)
    end
    it 'delete participant with associations and force is true and single team_user' do
      allow(participant).to receive(:team).and_return(team)
      allow(team).to receive(:teams_users).and_return(length: 1)
      expect(participant.delete(true)).to eq(participant)
    end
    it 'raises error, delete participant with associations and force is nil' do
      allow(participant).to receive(:team).and_return(team)
      expect{participant.delete(nil)}.to raise_error.with_message("Associations exist for this participant.")
    end
  end
  • force_delete : Method called inside #delete to remove the participant and all necessary associations. Testing of this method is covered through the testing of #delete. Therefore, there are not explicit test cases written.
  • topic_name : Returns the topic name associated with a participant.
- mock used in the testing of an existing topic name by simulating the return of a participant's topic when asked
  describe '#topic_name' do
    it 'returns the participant topic name when nil' do
      expect(participant.topic_name).to eq('<center>—</center>')
    end
    it 'returns the participant topic name when not nil' do
      allow(participant).to receive(:topic).and_return(topic)
      expect(participant.topic_name).to eq("Hello world!")   
    end
  end
  • able_to_review : Checks and returns the review rights of a participant.
  describe '#able_to_review' do
    it 'returns true when can_review is true' do
      expect(participant.able_to_review).to eq(true)
    end
    it '#returns false when can_review is false' do
      expect(participant3.able_to_review).to eq(false)
    end
  end
  • email : Sends an email to a participant, verifying an assignment registration.
  describe '#email' do
    it 'sends an email to the participant' do
      expect {participant.email("Missing 'pw'", "Missing 'home_page'")}.to change{
		ActionMailer::Base.deliveries.count}.by(1)
    end
  end
  • scores : Returns a hash of values that are applicable to a participant's assignment scores (i.e. { participant information, assignment question information, total scores })
- how?
  describe '#score' do
    it 'Get participant score within a round' do
      questions = {:review=>[question1],:review1=> [question]}
      test = [questionnaire,questionnaire1]

      allow(participant.assignment).to receive(:questionnaires).and_return(test)
      assessment=double("review")	
      
      test.each do |q|
        assignment_questionnaire_map=double("assignment_questionnaire",:used_in_round=>nil)
        if q.id==2	
          assignment_questionnaire_map=double("assignment_questionnaire",:used_in_round=>1)
        end 
        allow(AssignmentQuestionnaire).to receive(:find_by).with(assignment_id: 1, questionnaire_id: q.id).and_return(assignment_questionnaire_map)
        assessment=double("review")
        allow(q).to receive(:get_assessments_for).with(participant).and_return(assessment)
	allow(Answer).to receive(:compute_scores).with(assessment,questions[:review]).and_return(5)
	allow(Answer).to receive(:compute_scores).with(assessment,questions[:review1]).and_return(6)
      end
      
      allow(participant.assignment).to receive(:compute_total_score).with(any_args).and_return(75)
      check = participant.scores(questions)
      
      expect(check).to include(:participant => participant)
      expect(check[:review1].to_s).to include({:assessments=> assessment,:scores=>6}.to_s)
      expect(check[:review].to_s).to eq({:assessments=>assessment,:scores=>5}.to_s)
      expect(check).to include(:total_score => 75)
    end
  end
  • get_permissions : Returns the permissions association with a participant based on participant type (i.e. participant, reader, reviewer, submitter).
  describe '#get_permissions' do
    it 'returns the permissions of participant' do
      expect(Participant.get_permissions('participant')).to contain_exactly(
		[:can_submit, true], [:can_review, true], [:can_take_quiz, true])
    end
    it 'returns the permissions of reader' do
      expect(Participant.get_permissions('reader')).to contain_exactly(
		[:can_submit, false], [:can_review, true], [:can_take_quiz, true])
    end
    it 'returns the permissions of reviewer' do
      expect( Participant.get_permissions('reviewer')).to contain_exactly(
		[:can_submit, false], [:can_review, true], [:can_take_quiz, false])
    end
    it 'returns the permissions of submitter' do
      expect(Participant.get_permissions('submitter')).to contain_exactly(
		[:can_submit, true], [:can_review, false], [:can_take_quiz, false])
    end
  end
  • get_authorization : Returns the participant's authorization role based on its access rights (can_submit,can_review,can_take_quiz).
  describe '#get_authorization' do
    it 'returns participant when no arguments are passed' do
      expect(Participant.get_authorization(nil, nil, nil)).to eq('participant')
    end
    it 'returns reader when no arguments are passed' do
      expect(Participant.get_authorization(false, true, true)).to eq('reader')
    end
    it 'returns submitter when no arguments are passed' do
      expect(Participant.get_authorization(true, false, false)).to eq('submitter')
    end
    it 'returns reviewer when no arguments are passed' do
      expect(Participant.get_authorization(false, true, false)).to eq('reviewer')
    end
  end
  • sort_by_name : Returns the sorted array of participants by name.
  describe '#sort_by_name' do
    it 'returns a sorted list of participants alphabetical by name' do
      unsorted = [participant3, participant, participant2]
      sorted = [participant, participant2, participant3 ]
      expect(Participant.sort_by_name(unsorted)).to eq(sorted)
    end
  end

Running Tests

Run all Rspec tests from the terminal :

 rspec spec/models/participant_spec.rb

Run a specific Rspec test from the terminal :

 rspec spec/models/participant_spec.rb:{line number}

Run Rspec tests from terminal with mutations to test quality of test cases :

 RAILS_ENV=test bundle exec mutant -r ./config/environment --use rspec Participant
- more information about mutation testing can be found in the link provided in the External Links section of this wiki.

Testing Outcomes

Through the implementation of quality unit tests, 100.00% path coverage was achieved.

External links

Expertiza Github with implemented tests for Participant model :

- tests can be found within rspec/models/participant_spec.rb

Mutant gem description and use :