CSC/ECE 517 Fall 2019 - E1949. Write Unit Tests for Importing assignment participants and import glitches
E1949. Write Unit Tests for Importing assignment participants and import glitches
This page is a description of Expertiza OSS project E.1949 Write Unit Tests for Importing assignment participants and import glitches.
Expertiza Introduction
Expertiza is a web application where students can submit and peer-review learning objects (articles, code, web sites, etc). It is used in select courses at NC State and by professors at several other colleges and universities.
Problem Background
The import feature is the most helpful feature for instructors to set up assignments. The instructors usually have a list of students, teams, etc from their learning management system. Being able to import these into expertiza saves a lot of time when setting up an assignment.
Problem Statement
- Importing participants redirects to a confirmation screen listing the users that are going to be imported but the users do not seem to be imported.
- This is an intermittent issue that can be addressed through a test case.
Test Plan
Task 1. Write a test case to import participants.
We looked into the files responsible for importing assignment participants. The imported file goes through the following process.
- Add one line to expect that #create_new_user method in import_file_helper is NOT called in each test case that the user HAS an account, and do the opposite in case the user DOES NOT HAVE an account.
#spec/models/assignment_particpant_spec.rb describe ".import" do context 'when record is empty' do it 'raises an ArgumentError' do expect { AssignmentParticipant.import({}, nil, nil, nil) }.to raise_error(ArgumentError, 'No user id has been specified.') end end context 'when the record has less than 4 items' do it 'raises an ArgumentError' do row = {name: 'no one', fullname: 'no one', email: 'no_one@email.com'} expect(ImportFileHelper).not_to receive(:create_new_user) expect { AssignmentParticipant.import(row, nil, nil, nil) }.to raise_error('The record containing no one does not have enough items.') end end context 'when certain assignment cannot be found' do it 'creates a new user based on import information and raises an ImportError' do allow(Assignment).to receive(:find).with(1).and_return(nil) expect(ImportFileHelper).to receive(:create_new_user) expect { AssignmentParticipant.import(row, nil, {}, 1) }.to raise_error('The assignment with id "1" was not found.') end end allow(AssignmentParticipant).to receive(:exists?).with(user_id: 1, parent_id: 1).and_return(false) allow(AssignmentParticipant).to receive(:create).with(user_id: 1, parent_id: 1).and_return(participant) allow(participant).to receive(:set_handle).and_return('handle') expect(ImportFileHelper).to receive(:create_new_user) expect(AssignmentParticipant.import(row, nil, {}, 1)).to be_truthy end end end
Task 2. Write a test case to import topics with special cases.
- Thoroughly test the #import method in the sign_up_topic model. This includes the following test cases:
- The record is empty
- The record is not empty and the topic is not existing, including special cases
- The record is not empty and the topic is existing, including special cases
#spec/models/sign_up_topic_spec.rb describe SignUpTopic do let(:topic) { build(:topic) } describe '.import' do context 'when record is empty' do it 'raises an ArgumentError' do expect { SignUpTopic.import({}, nil, nil) }.to raise_error(ArgumentError, 'The CSV File expects the format: Topic identifier, Topic name, Max choosers, Topic Category (optional), Topic Description (Optional), Topic Link (optional).') end end context 'when record is not empty' do let(:row) do {topic_identifier: 'identifier', topic_name: 'name', max_choosers: 'chooser', category: 'category', description: 'description', link: 'link'} end let(:session) do {assignment_id: 1} end let(:attributes) do {topic_identifier: 'identifier', topic_name: 'name', max_choosers: 'chooser', category: 'category', description: 'description', link: 'link'} end context 'when the topic is not found' do it 'creates a new sign up topic' do allow(SignUpTopic).to receive_message_chain(:where, :first).with(topic_name: row[:topic_name], assignment_id: session[:assignment_id]).with(no_args).and_return(nil) allow(ImportTopicsHelper).to receive(:define_attributes).with(row).and_return(attributes) allow(ImportTopicsHelper).to receive(:create_new_sign_up_topic).with(attributes, session).and_return(true) expect(ImportTopicsHelper).to receive(:create_new_sign_up_topic).with(attributes, session) SignUpTopic.import(row, session, nil) end end context 'when the topic is found' do it 'changes the max_chooser and topic_identifier of the existing topic' do allow(SignUpTopic).to receive_message_chain(:where, :first).with(topic_name: row[:topic_name], assignment_id: session[:assignment_id]).with(no_args).and_return(topic) allow(topic).to receive(:save).with(no_args).and_return(true) expect(topic).to receive(:save).with(no_args) SignUpTopic.import(row, session, nil) end end end end
Task 3. Write a test case to handle import conflicts. ( Issue #329 and Issue #328)
- Thoroughly test the #import method in the team model. This includes the following test cases:
- Duplicates exist. Ignore the new team.
- Duplicates exist. Replace the existing team with the new team.
- Duplicates exist. Insert any new members to the existing team.
- Duplicates exist. Rename the new team and import.
- Duplicates exist. Rename the existing team and import.
describe '.import' do context 'when row is empty and has_column_names option is not true' do it 'raises an ArgumentError' do expect { Team.import({}, 1, {has_column_names: 'false'}, AssignmentTeam.new) } .to raise_error(ArgumentError, 'Not enough fields on this line.') end end context 'when there are duplicates in new teams with existing teams' do let(:row) do {teammembers: %w(member1 member2), teamname: 'name'} end let(:options) do {has_teamname: 'true_first'} end let(:id) {1} before(:each) do allow(Team).to receive_message_chain(:where, :first).with(["name =? && parent_id =?", row[:teamname], id]).with(no_args).and_return(team) allow(AssignmentTeam).to receive(:create_team_and_node).with(id).and_return(team) allow(team).to receive(:save).and_return(true) allow(team).to receive(:import_team_members) end context 'when choosing to ignore the new team' do it 'handles duplicates with "ignore" argument' do options[:handle_dups] = "ignore" allow(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "ignore", AssignmentTeam).and_return(nil) expect(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "ignore", AssignmentTeam).and_return(nil) Team.import(row, id, options, AssignmentTeam) end end context 'when choosing to replace the existing team with the new team' do it 'handles duplicates with "replace" argument' do options[:handle_dups] = "replace" allow(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "replace", AssignmentTeam).and_return(row[:teamname]) expect(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "replace", AssignmentTeam).and_return(row[:teamname]) Team.import(row, id, options, AssignmentTeam) end end context 'when choosing to insert any new members to existing team' do it 'handles duplicates with "insert" argument' do options[:handle_dups] = "insert" allow(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "insert", AssignmentTeam).and_return(nil) expect(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "insert", AssignmentTeam).and_return(nil) Team.import(row, id, options, AssignmentTeam) end end context 'when choosing to rename the new team and import' do it 'handles duplicates with "rename" argument' do options[:handle_dups] = "rename" allow(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "rename", AssignmentTeam).and_return(row[:teamname]) expect(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "rename", AssignmentTeam).and_return(row[:teamname]) Team.import(row, id, options, AssignmentTeam) end end context 'when choosing to rename the existing team and import' do it 'handles duplicates with "rename_existing" argument' do options[:handle_dups] = "rename_existing" allow(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "rename_existing", AssignmentTeam).and_return(row[:teamname]) expect(Team).to receive(:handle_duplicate).with(team, row[:teamname], id, "rename_existing", AssignmentTeam).and_return(row[:teamname]) Team.import(row, id, options, AssignmentTeam) end end end
describe '.handle_duplicate' do context 'when parameterized team is nil' do it 'returns team name' do expect(Team.handle_duplicate(nil, 'no name', 1, 'replace', CourseTeam.new)).to eq('no name') end end context 'when parameterized team is not nil' do context 'when handle_dups option is ignore' do it 'does not create the new team and returns nil' do expect(Team.handle_duplicate(team, 'no name', 1, 'ignore', CourseTeam.new)).to be nil end end context 'when handle_dups option is rename' do it 'returns new team name' do allow(Course).to receive(:find).with(1).and_return(double('Course', name: 'no course')) allow(Assignment).to receive(:find).with(1).and_return(double('Assignment', name: 'no assignment')) allow(Team).to receive(:generate_team_name).with('no course').and_return('new team name') allow(Team).to receive(:generate_team_name).with('no assignment').and_return('new team name') expect(Team.handle_duplicate(team, 'no name', 1, 'rename', CourseTeam.new)).to eq('new team name') expect(Team.handle_duplicate(team, 'no name', 1, 'rename', AssignmentTeam.new)).to eq('new team name') end end context 'when handle_dups option is replace' do it 'deletes the old team' do allow(team).to receive(:delete) expect(Team.handle_duplicate(team, 'no name', 1, 'replace', CourseTeam.new)).to eq('no name') end end context 'when handle_dups option is insert' do it 'does nothing and returns nil' do expect(Team.handle_duplicate(team, 'no name', 1, 'insert', CourseTeam.new)).to be nil end end # By the time this test is added (by E1949), the renaming existing team function does not exist yet, # so it should fail unless the function is implemented and the existing team is renamed and saved. context 'when handle_dups option is rename_existing' do it 'renames the existing team and returns nil' do allow(Course).to receive(:find).with(1).and_return(double('Course', name: 'no course')) allow(Assignment).to receive(:find).with(1).and_return(double('Assignment', name: 'no assignment')) allow(Team).to receive(:generate_team_name).with('no course').and_return('new team name') allow(Team).to receive(:generate_team_name).with('no assignment').and_return('new team name') allow(team).to receive(:name=).with('new team name') allow(team).to receive(:save) expect(team).to receive(:name=).with('new team name').exactly(2).times expect(team).to receive(:save).exactly(2).times expect(Team.handle_duplicate(team, 'no name', 1, 'replace_existing', CourseTeam.new)).to be nil expect(Team.handle_duplicate(team, 'no name', 1, 'replace_existing', AssignmentTeam.new)).to be nil end end end end
Result
Task 1
[[File:Task1.png] 500px]
Task 2
Task 3
Testing Video
To view the testing vedio, please click the link upon.