CSC/ECE 517 Fall 2018- Project E1848: Writing unit tests for assignment team.rb
The purpose of this project is to improve the coverage and quality of the unit tests for the assignment team model in Expertiza. This project comprised the program 3 assignment of CSC/ECE 517 in fall 2018 and is entitled "Project E1848: Writing unit tests for assignment_team.rb." The source code for this project is in pull request #1228 of the Expertiza project on GitHub.
Key Contributions
Out of the 30 methods defined for the model AssignmentTeam.rb, test case was written for only one. Our contribution was to successfully add test cases for all remaining 29 methods.
Hence, increasing the coverage from 5% to 100%.
The Class under Test
AssignmentTeam
This class handles all functionalities for a team linked to an assignment. Some of the functionalities include, get a list of participants in the team, get the team name, team score for the given assignment, submissions for this team (files) and (hyperlinks) and topic picked by the team. Add/or remove participants from the team. It also checks for any reviews the team may have gotten for their work. Export all teams in a CSV file, import files from CSV to form teams.
Test Plan
Test Design
Test Structure
Listed below are the functionalities and the Rspec unit tests corresponding to the function names along with a list of scenarios tested.
Function name: includes?(participant)
This function in AssignmentTeam.rb checks if the participant passed as argument is a member of the team or not. For this, we utilize factorybot to build a user and a participant1 as follows-:
let(:user1) { build(:student, id: 2) } let(:participant1) { build(:participant, id: 1) }
Test cases checked for are-:
1) when the team receives a user, that user is allowed to become a team participant. The method returns True for the given participant passed as argument.
context "when an assignment team has one participant" do it "includes one participant" do allow(team).to receive(:users).with(no_args).and_return([user1]) allow(AssignmentParticipant).to receive(:find_by).with(user_id: user1.id, parent_id: team.parent_id).and_return(participant1) expect(team.includes?(participant1)).to eq true end end
2) when the team receives a user with no arguments, that user is not allowed to become a team participant. The method returns False for the given participant passed as argument.
context "when an assignment team has no users" do it "includes no participants" do allow(team).to receive(:users).with(no_args).and_return([]) expect(team.includes?(participant1)).to eq false end end
Function name: parent_model
This function in AssignmentTeam.rb always provides the name of the parent model which is Assignment.
Hence, the unit test also always checks if the response of this method is the string "Assignment" or not.
it "provides the name of the parent model" do expect(team.parent_model).to eq "Assignment" end
Function name: self.parent_model(id)
This function in AssignmentTeam.rb takes in as argument id of the current Assignment for the team and returns an instance of the parent model.
Hence the unit test checks if the instance returned by this method for a given assignment id, matches the assignment or not.
it "provides the instance of the parent model" do allow(Assignment).to receive(:find).with(1).and_return(assignment) expect(AssignmentTeam.parent_model(1)).to eq assignment end
Function name: fullname
This function in AssignmentTeam.rb print out the name for the current class instance. for this we first build an assignment team instance and assign it the name "abcd".
Hence the unit test checks if the assignment team has a name, and returns that same name.
context "when the team has a name" do it "provides the name of the class" do team = build(:assignment_team, id: 1, name: "abcd") expect(team.fullname).to eq "abcd" end end
Function name: review_map_type
This function in AssignmentTeam.rb always provides the name of the review map type which is ReviewResponseMap.
Hence, the unit test also always checks if the response of this method is the string "ReviewResponseMap" or not.
it "provides the review map type" do expect(team.review_map_type).to eq "ReviewResponseMap" end
Function name: self.prototype
This function in AssignmentTeam.rb implements the prototype pattern by returning a new instance of the class AssignmentTeam.
The unit test checks if the response is a new instance of the class or not.
it "provides the instance of the AssignmentTeam" do expect(AssignmentTeam).to receive(:new).with(no_args) AssignmentTeam.prototype end
Test Coverage
The model has a total of 237 lines, out of which 127 were relevant lines. We achieved 100% coverage with avg hits per line at 2.3 (the number of times each specific line was run during the test suite)
Stubs for Isolating the UUT
DRY Testing Practices
Factories and the let RSPEC Helper Method
Contexts
Testing Framework
RSpec Introduction
RSPEC is a testing framework for Ruby for behavior-driven development (BDD) licensed under MIT. It is inspired by JBehave and contains fully integrated JMock based framework which has a very rich and powerful DSL (domain-specific language) which resembles a natural language specification. Composed of multiple libraries structured to work together, RSpec provides encapsulated testing via the describe block to specify the behavior of the class and the context for the unit test case.
Why RSpec?
RSpec is easy to learn and implement and can be used with other testing tools like Cucumber and Minitest independently. It is extremely powerful for testing states with complicated setup and also helps in tearing down complex code to access the objects required for testing RSpec semantics encourage agile thinking and practice and it structures the tests in a more intuitive way.
Bugs Detected
- I don't think we need this section
Results
Future Work
DRY principle could be cleaned up a little more. Sometimes it became necessary to use the let or build helper methods in each unit test. They may all be consolidated at the beginning.
Some more edge cases could be thought of for each method, and tests written for those. Although, we have tried to cover as many as possible.
Additionally, in the future, the code may also be refactored with a more efficient tool.
Test coverage through quality tests consistently added throughout the development of the Expertiza project should be the future work of the project.
References
1. Expertiza
2. Expertiza Wikipedia
3. Expertiza Github Repository
4. RSpec - Relish
5. Engineering Software as a Service