CSC/ECE 517 Spring 2024 - E2410 Reimplement View for results of bidding
Expertiza
Expertiza is an open-source web application built on Ruby on Rails that enables instructors to create customized assignments with topic lists for students to choose from. It facilitates team formation, allowing students to collaborate on assignments and projects. Expertiza supports peer review processes where students can provide feedback on each other's submissions across various document formats, including URLs and wiki pages. This freely available platform provides a flexible and comprehensive solution for managing assignments, teamwork, and peer evaluations.
Introduction
The project focuses on decluttering the bidding view interface to offer a more intuitive user experience. This will not only improve readability and maintainability but also ensure the code adheres to design principles such as the Single Responsibility Principle. The initiative promises to reduce redundancy and elevate the overall functionality of the platform, paving the way for a more robust and user-centric application.
Problem Statement
The reimplementation project entails:
- Enhance the user interface of the bidding view to make it less cluttered and more user-friendly.
- Refactor the assignment_controller.rb by extracting the bidding logic into a separate controller, bidding_logic_controller.rb, to adhere to SRP.
- Improve the readability and maintainability of the codebase by implementing meaningful method names and adhering to design principles.
- Reduce redundancy in the code and promote reusability across different models within the platform.
Plan for Reimplementation of GradesController
Refactoring assignment Controller:
File: app/controllers/assignment_controller.rb
Refactor the bidding_details method to a more clear method nameEnhancing code clarity. Separate the bidding logic from the assignment controller to adhere to the Single Responsibility Principle (SRP).
Improving Bidding View:
Files: app/views/assignments/edit/_topics.html.erb
, app/views/assignments/n
, bidding_details.html.erb
Consolidate the bidding details summary view into a single table for improved clarity and organization. Implement interactive features such as modals or tooltips to provide additional context or information.
Meaningful Method Names:
Files: app/controllers/assignment_controller.rb
, app/models/assignment.rb
, app/models/team.rb
, app/models/bid.rb
Review existing method names and replace generic or unclear names with descriptive ones that accurately reflect their purpose and functionality ensuring consistency.
Adherence to Design Principles:
Files: app/controllers/assignment_controller.rb
, app/models/assignment.rb
, app/models/team.rb
, app/models/bid.rb
Refactor code segments to eliminate redundancy and promote code reusability. Stick to the design principles listed below.
Design Principles
Single Responsibility Principle (SRP):
- Each action in the GradesController will be responsible for a specific task related to managing grades.
- Actions will be refactored to separate concerns such as data retrieval, computation, and view rendering.
- For example, the `view` action will focus solely on retrieving grading data and rendering the grading report.
Don't Repeat Yourself (DRY) Principle:
- Code duplication in the GradesController will be eliminated by extracting common functionality into helper methods or modules.
- Repetitive logic, such as retrieving questions or calculating penalties, will be refactored to promote code reusability and maintainability.
Dependency Inversion Principle (DIP):
- The GradesController will depend on abstractions, interfaces, or higher-level modules instead of concrete implementations.
- Dependency injection or inversion of control will be used to decouple the controller from specific database or service implementations.
RSpec Testing
The assignment_controller_spec.rb has existing automated rspec tests in place. Furthermore following tests were added to the code to ensure the functionality is working as expected and thereby increasing code coverage:-
-> assignment_controller_spec.rb
describe '#bidding_details' do it 'assigns necessary variables and renders bidding_details template' do allow(Assignment).to receive(:find).with('1').and_return(assignment) allow(assignment).to receive(:sign_up_topics).and_return([double('SignUpTopic', id: 1)]) allow(Bid).to receive(:where).with(topic_id: 1).and_return([]) allow(assignment).to receive(:calculate_percentage_of_teams_getting_choices).and_return({}) allow(assignment).to receive(:teams_bidding_for_each_topic).and_return({}) allow(assignment).to receive(:assigned_teams_for_topics).and_return({}) get :bidding_details, params: { id: 1 } expect(assigns(:assignment)).to eq(assignment) expect(assigns(:bids_by_topic)).to eq({ 1 => [] }) expect(response).to render_template('bidding_details') end end describe '#bidding_details_for_topic' do it 'assigns necessary variables and renders bidding_details_for_topic template' do topic = double('SignUpTopic', id: 1) bids = [double('Bid')] allow(SignUpTopic).to receive(:includes).with(:bids).and_return(SignUpTopic) allow(SignUpTopic).to receive(:find).with(1).and_return(topic) allow(topic).to receive(:bids).and_return(bids) get :bidding_details_for_topic, params: { topic_id: 1 }, format: :js expect(assigns(:topic)).to eq(topic) expect(assigns(:bids)).to eq(bids) expect(response).to render_template('bidding_details_for_topic') end end
Similarly, the file assignment_spec.rb have the automated rspec tests in them, Few more test case were added to verify the functionalities added.
-> assignment_spec.rb
describe '#calculate_percentage_of_teams_getting_choices' do it 'calculates the percentage of teams getting their choices' do # Mock necessary objects for the test assignment = build(:assignment) team1 = build(:team) team2 = build(:team) topic1 = build(:sign_up_topic, assignment_id: assignment.id) topic2 = build(:sign_up_topic, assignment_id: assignment.id) bid1 = build(:bid, team: team1, topic: topic1) bid2 = build(:bid, team: team1, topic: topic2) bid3 = build(:bid, team: team2, topic: topic2) allow(assignment).to receive(:sign_up_topics).and_return([topic1, topic2]) allow(Team).to receive(:where).and_return([team1, team2]) allow(team1).to receive(:bid_for_topic).with(topic1).and_return(bid1) allow(team1).to receive(:bid_for_topic).with(topic2).and_return(bid2) allow(team2).to receive(:bid_for_topic).with(topic2).and_return(bid3) # Perform the calculation percentages = assignment.calculate_percentage_of_teams_getting_choices # Perform your assertions here expect(percentages[1]).to eq(50.0) expect(percentages[2]).to eq(100.0) end end describe '#teams_bidding_for_each_topic' do it 'returns teams bidding for each topic' do # Mock necessary objects for the test assignment = build(:assignment) topic1 = build(:sign_up_topic, id: 1) topic2 = build(:sign_up_topic, id: 2) team1 = build(:team) team2 = build(:team) bid1 = build(:bid, team: team1, topic: topic1) bid2 = build(:bid, team: team1, topic: topic2) bid3 = build(:bid, team: team2, topic: topic2) allow(assignment).to receive_message_chain(:sign_up_topics, :includes).and_return([topic1, topic2]) allow(topic1).to receive_message_chain(:bids, :map).and_return([['Team1', 1]]) allow(topic2).to receive_message_chain(:bids, :map).and_return([['Team1', 1], ['Team2', 2]]) # Call the method result = assignment.teams_bidding_for_each_topic # Perform assertions expect(result[1]).to eq([['Team1', 1]]) expect(result[2]).to eq([['Team1', 1], ['Team2', 2]]) end end describe '#bidding_info_by_topic' do it 'returns bidding information by topic' do # Mock necessary objects for the test assignment = build(:assignment) topic1 = build(:sign_up_topic, id: 1) topic2 = build(:sign_up_topic, id: 2) team1 = build(:team, name: 'Team1') team2 = build(:team, name: 'Team2') bid1 = build(:bid, team: team1, priority: 1) bid2 = build(:bid, team: team2, priority: 2) allow(assignment).to receive_message_chain(:sign_up_topics, :includes).and_return([topic1, topic2]) allow(topic1).to receive_message_chain(:bids, :includes, :map).and_return([{ team_name: 'Team1', bid_priority: 1 }]) allow(topic2).to receive_message_chain(:bids, :includes, :map).and_return([{ team_name: 'Team2', bid_priority: 2 }]) # Call the method result = assignment.bidding_info_by_topic # Perform assertions expect(result[1]).to eq([{ team_name: 'Team1', bid_priority: 1 }]) expect(result[2]).to eq([{ team_name: 'Team2', bid_priority: 2 }]) end end describe '#assigned_teams_for_topics' do it 'returns assigned teams for each topic' do # Mock necessary objects for the test assignment = build(:assignment) topic1 = build(:sign_up_topic, id: 1) topic2 = build(:sign_up_topic, id: 2) team1 = build(:team, name: 'Team1') team2 = build(:team, name: 'Team2') allow(assignment).to receive_message_chain(:sign_up_topics, :includes).and_return([topic1, topic2]) allow(topic1).to receive_message_chain(:assigned_teams, :map).and_return(['Team1']) allow(topic2).to receive_message_chain(:assigned_teams, :map).and_return(['Team2']) # Call the method result = assignment.assigned_teams_for_topics # Perform assertions expect(result[1]).to eq(['Team1']) expect(result[2]).to eq(['Team2']) end end
Team
Mentor:
- Anvitha Reddy Gutha (agutha@ncsu.edu)
Members:
- Shiva Vara Prasad Kandhagatla (skandha@ncsu.edu)
- Sai Santhosh Garlapati (sgarlap@ncsu.edu)
- Chinmay Walinjkar (cpwalinj@ncsu.edu)