CSC/ECE 517 Spring 2024 - E2440 Testing for questionnaire helper, review bids helper

From Expertiza_Wiki
Jump to navigation Jump to search

This page describes the changes made for the Spring 2024 E2440. Testing for questionnaire_helper, review_bids_helper

Project Overview

Problem Statement

Our project involves writing test cases for the `questionnaire_helper` and `review_bids_helper` files in Expertiza, an open-source assignment/project management portal built on the Ruby on Rails framework. This platform facilitates collaborative learning and feedback among both instructors and students. Instructors can create and customize assignments, define topics for student sign-ups, and manage teams for various projects. Students, on the other hand, can sign up for topics, form teams, and participate in peer reviews to enhance each other's learning experiences. Our goal is to develop comprehensive test plans and increase code coverage for these helper files to ensure their reliability and effectiveness in the Expertiza platform.

Current Code Coverage

Objectives

  • Develop test plans/scenarios for questionnaire_helper.rb
  • Develop test plans/scenarios for review_bids_helper.rb
  • Improve code coverage for questionnaire_helper.rb
  • Improve code coverage for review_bids_helper.rb

Files Involved

  • Questionnaire_helper.rb: /app/helpers/questionnaire_helper.rb
  • Review_bids_helper.rb: /app/helpers/review_bids_helper.rb

Mentor

  • Muhammet Mustafa Olmez (molmez@ncsu.edu)

Team Members

  • Neha Vijay Patil (npatil2@ncsu.edu)
  • Prachit Mhalgi (psmhalgi@ncsu.edu)
  • Sahil Santosh Sawant (ssawant2@ncsu.edu)

Class and Method Overview

QuestionnaireHelper

The QuestionnaireHelper module contains several methods to assist with managing questionnaires in expertiza. QuestionnaireHelper provides methods for adjusting advice size, updating questionnaire questions, and creating questionnaire instances based on types. It also defines constants to facilitate these functionalities. These methods are likely used within the application to handle questionnaire-related tasks efficiently. Let's break down the class and its methods:

Constants

CSV_QUESTION, CSV_TYPE, CSV_PARAM, CSV_WEIGHT

  - These constants define indices for specific columns in a CSV file.

QUESTIONNAIRE_MAP

  - This constant is a hash that maps questionnaire types to their respective questionnaire classes.
  - It's used by the `questionnaire_factory` method to determine the appropriate class to instantiate.

Methods

1. adjust_advice_size(questionnaire, question)

  - This method adjusts the size of advice associated with a given question in a questionnaire.
  - Parameters:
    - `questionnaire`: The questionnaire object.
    - `question`: The question object whose advice size needs adjustment.
  - Functionality:
    - Checks if the question is a `ScoredQuestion`.
    - Deletes any existing advice for the question outside the score range.
    - Iterates over the score range and ensures each score has an associated advice.
    - Deletes any duplicate advice records.
  

2. update_questionnaire_questions

  - This method updates attributes of questionnaire questions based on form data, without modifying unchanged attributes.
  - Functionality:
    - Checks for presence of `params[:question]`.
    - Iterates through each question and its attributes in the parameters.
    - Compares each attribute's current value with the new value from the parameters and updates if changed.
    - Saves the question.

3. questionnaire_factory(type)

  - This method acts as a factory to create an appropriate questionnaire object based on the type provided.
  - Parameters:
    - `type`: The type of questionnaire.
  - Functionality:
    - Retrieves the questionnaire class from `QUESTIONNAIRE_MAP` based on the provided type.
    - If the type is not found in the map, it sets an error flash message.
    - Otherwise, it initializes a new instance of the corresponding questionnaire class and returns it.

ReviewBidsHelper

This Ruby module, `ReviewBidsHelper` serves as a helper module for views related to reviewing bids in expertiza. `ReviewBidsHelper` provides helper methods for rendering topic rows and determining the background color for topics based on their bid status and the number of participants. These methods are likely used in the views associated with reviewing bids in the application. Let's break down the class and its methods:

Methods

1. get_intelligent_topic_row_review_bids(topic, selected_topics, num_participants)

  - This method seems to be responsible for generating HTML markup for a row in a table displaying topics for review bids.
  - Parameters:
    - `topic`: Represents a specific topic being reviewed.
    - `selected_topics`: An array of topics that have been selected.
    - `num_participants`: The number of participants involved in the review process.
  - Functionality:
    - Iterates through the `selected_topics`.
    - Depending on the conditions (whether the topic is selected and not waitlisted, or selected and waitlisted), it generates a specific row HTML.
    - Returns the generated row HTML as safe HTML.

2. get_topic_bg_color_review_bids(topic, num_participants)

  - This method calculates the background color for a topic based on the number of participants and the number of bids for that topic.
  - Parameters:
    - `topic`: Represents the topic for which the background color is being determined.
    - `num_participants`: The total number of participants.
  - Functionality:
    - Calculates the number of bids for the given `topic`.
    - Determines the proportion of bids compared to the total number of participants and adjusts the color accordingly.
    - Returns a string representing the RGB value of the background color.

Objective 1: Develop code testing scenarios for questionnaire_helper

  • Single Responsibility Principle (SRP):

Each method within the QuestionnaireHelper class appears to adhere to the SRP by focusing on a single task or responsibility. For example, the adjust_advice_size method is responsible for adjusting the size of advice based on questionnaire scores, while the questionnaire_factory method is responsible for creating instances of questionnaire types based on the given type parameter. This adherence ensures that each method has a clear and distinct purpose, promoting code maintainability and readability.

  • Open/Closed Principle (OCP):

While not explicitly evident in the provided snippets, the design allows for extension without modification, which aligns with the OCP. For instance, new types of questionnaires can be added without altering existing code by simply extending the questionnaire_factory method to accommodate the new types.

  • Dependency Injection Principle (DIP):

The methods in the QuestionnaireHelper class accept various objects (e.g., questionnaire, scored_question) as parameters, adhering to the principle of dependency injection. By accepting dependencies from external sources rather than creating them internally, these methods become more flexible and easily testable.

  • Factory Method Pattern:

The questionnaire_factory method can be seen as exhibiting characteristics of the factory method pattern. It dynamically creates instances of different questionnaire types based on the given type parameter, promoting flexibility and extensibility.

After reviewing the QuestionnaireHelper class, we identified three methods in the class that require testing. These methods are as follows:

  • adjust_advice_size
  • questionnaire_factory
  • update_questionnaire_questions

adjust_advice_size

Method Description

The .adjust_advice_size method is being described. This method likely adjusts the size of advice related to questions based on certain conditions.

Test Setup

Mock objects are set up using let statements. These include a questionnaire, a scored_question, a non_scored_question, and a question_advice. Each of these mock objects is prepared with predefined attributes that mimic the behavior of actual objects in the system.

Test Contexts

  • When Question is a ScoredQuestion: This context tests the behavior when the question is a scored question. It sets up expectations related to the adjustment of advice size based on the questionnaire scores.
 context 'when question is a ScoredQuestion' do
      it 'adjusts advice size based on questionnaire scores' do
    allow(QuestionAdvice).to receive(:where).and_return([])
    allow(QuestionAdvice).to receive(:new).and_return(double('QuestionAdvice', save: true))
    allow(scored_question).to receive(:is_a?).with(ScoredQuestion).and_return(true)
    described_class.adjust_advice_size(questionnaire, scored_question)
    expect(QuestionAdvice).to have_received(:where).exactly(10).times
    expect(scored_question.question_advices.size).to eq(10)
  end
    end

  • When Question is Not a ScoredQuestion: This context tests the behavior when the question is not a scored question. It verifies that in this case, the advice size is not adjusted.
context 'when question is not a ScoredQuestion' do
      it 'does not adjust advice size' do
        allow(QuestionAdvice).to receive(:where)
        allow(QuestionAdvice).to receive(:new)
        allow(scored_question).to receive(:is_a?).with(ScoredQuestion).and_return(false)
        described_class.adjust_advice_size(questionnaire, non_scored_question)
        expect(QuestionAdvice).not_to have_received(:where)
        expect(QuestionAdvice).not_to have_received(:new)
      end
    end

Expectations

Each test contains an it block with an expectation. These expectations use allow and expect statements to verify the behavior of the method under different conditions.

questionnaire_factory

Method Description

The .questionnaire_factory method is described. It seems to be a factory method responsible for creating instances of different questionnaire types based on the given type parameter.

Test Setup

Mock objects are set up using let statements. These include a topic, a review_bid, and the number of participants (num_participants). Each of these mock objects is prepared with predefined attributes that mimic the behavior of actual objects in the system.

Test Contexts

  • When Given a Valid Type: This context verifies the behavior when a valid questionnaire type is provided. It expects that calling questionnaire_factory with a valid type results in an instance of the specified questionnaire type (ReviewQuestionnaire).
 context 'when given a valid type' do
      it 'returns an instance of the specified questionnaire type' do
        questionnaire_type = 'ReviewQuestionnaire'
        expect(helper.questionnaire_factory(questionnaire_type)).to be_an_instance_of(ReviewQuestionnaire)
      end

  • When Given an Invalid Type: This context tests how the method handles an invalid questionnaire type. It expects that calling questionnaire_factory with an invalid type sets an error flash message indicating that the questionnaire type is undefined.
context 'when given an invalid type' do
      it 'sets an error flash message' do
        questionnaire_type = 'UnknownQuestionnaire'
        expect { helper.questionnaire_factory(questionnaire_type) }.to change { flash[:error] }.from(nil).to('Error: Undefined Questionnaire')
      end
    end

Expectations

Each test contains an it block with an expectation. These expectations use expect and change statements to verify the behavior of the method under different conditions.

update_questionnaire_questions

We did not implement test cases for this method because it was already covered in last semester by previous team.

Objective 2: Develop code testing scenarios for review_bids_helper

  • Single Responsibility Principle (SRP):

Each method within the ReviewBidsHelper class seems to adhere to the SRP. For example, get_intelligent_topic_row_review_bids is responsible for generating HTML code for topic rows, while get_topic_bg_color_review_bids determines the background color for a topic. This adherence ensures that each method has a clear and distinct purpose, enhancing maintainability and readability.

  • Factory Method Pattern:

Although not explicitly labeled as a factory method, get_intelligent_topic_row_review_bids can be interpreted as following a similar pattern. It dynamically generates HTML code based on different scenarios, akin to a factory producing instances of objects. This promotes flexibility and extensibility in generating HTML representations of topics.

After reviewing the ReviewBidsHelper module, we identified two methods that require testing:

get_intelligent_topic_row_review_bids

Objective

Verify that the method get_intelligent_topic_row_review_bids correctly renders the topic row for the topics table in review_bids/show.html.erb. The #get_intelligent_topic_row_review_bids method is being described. This method likely generates HTML code for displaying topic rows based on certain conditions.

Test Setup

Mock objects are set up using let statements. These include a topic, a selected_topic, the number of participants (num_participants), and a review_bid. Each of these mock objects is prepared with predefined attributes that mimic the behavior of actual objects in the system. For example, selected_topic is set with a topic ID of 1 and is not waitlisted initially.

Test Contexts

  • When Selected Topics are Present: This context tests the behavior of the method when there are selected topics. It sets up a selected topic that is not waitlisted and expects the generated HTML to include a table row with a yellow background.
context 'when selected topics are present' do
      it 'returns HTML code for topic row with appropriate background color' do
        selected_topic = instance_double('SelectedTopic')
        allow(selected_topic).to receive(:topic_id).and_return(1)
        allow(selected_topic).to receive(:is_waitlisted).and_return(false)
        selected_topics = [selected_topic]

        expect(helper.get_intelligent_topic_row_review_bids(topic, selected_topics, num_participants)).to include('<tr bgcolor="yellow">')
      end
    end
  • When Selected Topic is Waitlisted: This context tests the behavior when the selected topic is waitlisted. It sets up a selected topic that is waitlisted and expects the generated HTML to include a table row with a light gray background.
context 'when selected topic is waitlisted' do
      it 'returns HTML code for topic row with appropriate background color' do
        selected_topic = instance_double('SelectedTopic')
        allow(selected_topic).to receive(:topic_id).and_return(1)
        allow(selected_topic).to receive(:is_waitlisted).and_return(true)
        selected_topics = [selected_topic]

        expect(helper.get_intelligent_topic_row_review_bids(topic, selected_topics, num_participants)).to include('<tr bgcolor="lightgray">')
      end
    end
  • When Selected Topics are Not Present: This context checks what happens when there are no selected topics. It mocks a method (get_topic_bg_color_review_bids) to return a specific background color and expects the generated HTML to include a table row with that background color.
context 'when selected topics are not present' do
      it 'returns HTML code for topic row with appropriate background color' do
        allow(helper).to receive(:get_topic_bg_color_review_bids).and_return('rgb(255,255,255)')
        selected_topics = []

        expect(helper.get_intelligent_topic_row_review_bids(topic, selected_topics, num_participants)).to include('<tr id="topic_1" style="background-color:rgb(255,255,255)">')
      end
    end
  • When Selected Topics are Nil: This context tests how the method handles cases where the selected topics parameter is nil. It expects the generated HTML to include a table row with a specific background color.
context 'when selected topics are nil' do
      it 'returns HTML code for topic row with appropriate background color' do
        selected_topics = nil

        expect(helper.get_intelligent_topic_row_review_bids(topic, selected_topics, num_participants)).to include('<tr id="topic_1" style="background-color:rgb(47,352,0)">')
      end
    end
  end

Expectations

Each context contains an it block with an expectation. These expectations use expect statements to verify that the HTML generated by the method meets certain criteria, such as containing specific table row elements with appropriate background colors.


get_topic_bg_color_review_bids

Objective

Verify that the method get_topic_bg_color_review_bids correctly calculates the background color for a topic in the review_bids/show.html.erb template. The #get_topic_bg_color_review_bids method is being described. This method likely determines the background color for a topic based on certain conditions.

Test Setup

Mock objects are set up using let statements. These include a topic, a review_bid, and the number of participants (num_participants). Each of these mock objects is prepared with predefined attributes that mimic the behavior of actual objects in the system.

Test Contexts

  • Returns RGB Color Code: This test checks if the method returns an RGB color code for the topic background color. It sets up an expectation that the returned color code matches the pattern rgb(\d+,\d+,\d+), indicating it's in the correct format.
 context 'when there are no review bids' do
      it 'returns default RGB color code' do
        allow(ReviewBid).to receive(:where).with(signuptopic_id: topic.id).and_return([])

        expect(helper.get_topic_bg_color_review_bids(topic, num_participants)).to eq('rgb(47,352,0)')
      end
    end

  • When There Are No Review Bids: This context tests the behavior when there are no review bids associated with the topic. It sets up an expectation that the method returns a default RGB color code (rgb(47,352,0)), likely indicating a green color.
context 'when selected topic is waitlisted' do
      it 'returns HTML code for topic row with appropriate background color' do
        selected_topic = instance_double('SelectedTopic')
        allow(selected_topic).to receive(:topic_id).and_return(1)
        allow(selected_topic).to receive(:is_waitlisted).and_return(true)
        selected_topics = [selected_topic]

        expect(helper.get_intelligent_topic_row_review_bids(topic, selected_topics, num_participants)).to include('<tr bgcolor="lightgray">')
      end
    end

Expectations

Each test contains an it block with an expectation. These expectations use expect statements to verify the behavior of the method under different conditions.

Coverage Results

Questionnaire_helper

Review bids helper

Conclusion

This document outlines a thorough plan to enhance testing and code coverage for the questionnaire_helper and review_bids_helper files in Expertiza. With defined objectives, including developing detailed test plans and scenarios, the project aims to address current code coverage gaps. Notably, significant improvements were achieved in the review_bids_helper.rb file, with comprehensive test plans substantially increasing code coverage. Conversely, the questionnaire_helper.rb file saw marginal improvements, primarily due to existing full coverage in the update_questionnaire_questions method. Moving forward, the project will focus on implementing the outlined test plans, ensuring comprehensive testing and reliability for critical functionality across both helper files.

Links

  • Link to Expertiza repository: here
  • Link to Testing video: [1]
  • Link to pull request : here

References

1. Expertiza on GitHub (https://github.com/expertiza/expertiza)
2. The live Expertiza website (http://expertiza.ncsu.edu/)
3. Pluggable reputation systems for peer review: A web-service approach (https://doi.org/10.1109/FIE.2015.7344292)