Implement correct policy regarding whether there exist sufficient data for a measure

pull/1/head
Alex Basson 4 years ago
parent 7f23cb2d29
commit 2abf2d352a

@ -4,11 +4,19 @@ class Measure < ActiveRecord::Base
has_many :survey_item_responses, through: :survey_items has_many :survey_item_responses, through: :survey_items
def teacher_survey_items
@teacher_survey_items ||= survey_items.where("survey_item_id LIKE 't-%'")
end
def student_survey_items
@student_survey_items ||= survey_items.where("survey_item_id LIKE 's-%'")
end
def includes_teacher_survey_items? def includes_teacher_survey_items?
survey_items.where("survey_item_id LIKE 't-%'").any? teacher_survey_items.any?
end end
def includes_student_survey_items? def includes_student_survey_items?
survey_items.where("survey_item_id LIKE 's-%'").any? student_survey_items.any?
end end
end end

@ -8,8 +8,8 @@ class SurveyItemResponse < ActiveRecord::Base
scope :for_measures, ->(measures) { joins(:survey_item).where('survey_items.measure_id': measures.map(&:id)) } scope :for_measures, ->(measures) { joins(:survey_item).where('survey_items.measure_id': measures.map(&:id)) }
scope :for_measure, ->(measure) { joins(:survey_item).where('survey_items.measure_id': measure.id) } scope :for_measure, ->(measure) { joins(:survey_item).where('survey_items.measure_id': measure.id) }
scope :for_teacher_responses_for_measure, ->(measure) { for_measure(measure).where("survey_items.survey_item_id LIKE 't-%'") } scope :teacher_responses_for_measure, ->(measure) { for_measure(measure).where("survey_items.survey_item_id LIKE 't-%'") }
scope :for_student_responses_for_measure, ->(measure) { for_measure(measure).where("survey_items.survey_item_id LIKE 's-%'") } scope :student_responses_for_measure, ->(measure) { for_measure(measure).where("survey_items.survey_item_id LIKE 's-%'") }
def self.score_for_measure(measure:, school:, academic_year:) def self.score_for_measure(measure:, school:, academic_year:)
return nil unless SurveyItemResponse.sufficient_data?(measure: measure, school: school, academic_year: academic_year) return nil unless SurveyItemResponse.sufficient_data?(measure: measure, school: school, academic_year: academic_year)
@ -26,11 +26,17 @@ class SurveyItemResponse < ActiveRecord::Base
meets_student_threshold = true meets_student_threshold = true
if measure.includes_teacher_survey_items? if measure.includes_teacher_survey_items?
meets_teacher_threshold = SurveyItemResponse.for_teacher_responses_for_measure(measure).where(academic_year: academic_year, school: school).count >= TEACHER_RESPONSE_THRESHOLD teacher_survey_item_responses = SurveyItemResponse.teacher_responses_for_measure(measure).where(academic_year: academic_year, school: school)
average_number_of_survey_item_responses = teacher_survey_item_responses.count / measure.teacher_survey_items.count
meets_teacher_threshold = average_number_of_survey_item_responses >= TEACHER_RESPONSE_THRESHOLD
end end
if measure.includes_student_survey_items? if measure.includes_student_survey_items?
meets_student_threshold = SurveyItemResponse.for_student_responses_for_measure(measure).where(academic_year: academic_year, school: school).count >= STUDENT_RESPONSE_THRESHOLD student_survey_item_responses = SurveyItemResponse.student_responses_for_measure(measure).where(academic_year: academic_year, school: school)
average_number_of_survey_item_responses = student_survey_item_responses.count / measure.student_survey_items.count
meets_student_threshold = average_number_of_survey_item_responses >= STUDENT_RESPONSE_THRESHOLD
end end
meets_teacher_threshold and meets_student_threshold meets_teacher_threshold and meets_student_threshold

@ -29,33 +29,33 @@ feature 'School dashboard', type: feature do
let(:password) { 'winchester!' } let(:password) { 'winchester!' }
before :each do before :each do
survey_item_responses = []
survey_items_for_measure_1A_i.each do |survey_item| survey_items_for_measure_1A_i.each do |survey_item|
200.times do SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD.times do
SurveyItemResponse.create response_id: rand.to_s, academic_year: ay_2020_21, school: school, survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2020_21, school: school, survey_item: survey_item, likert_score: 4)
survey_item: survey_item, likert_score: 4
end end
end end
survey_items_for_measure_2A_i.each do |survey_item| survey_items_for_measure_2A_i.each do |survey_item|
200.times do SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD.times do
SurveyItemResponse.create response_id: rand.to_s, academic_year: ay_2020_21, school: school, survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2020_21, school: school, survey_item: survey_item, likert_score: 5)
survey_item: survey_item, likert_score: 5
end end
end end
survey_items_for_measure_4C_i.each do |survey_item| survey_items_for_measure_4C_i.each do |survey_item|
200.times do SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD.times do
SurveyItemResponse.create response_id: rand.to_s, academic_year: ay_2020_21, school: school, survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2020_21, school: school, survey_item: survey_item, likert_score: 1)
survey_item: survey_item, likert_score: 1
end end
end end
survey_items_for_subcategory.each do |survey_item| survey_items_for_subcategory.each do |survey_item|
200.times do 200.times do
SurveyItemResponse.create response_id: rand.to_s, academic_year: ay_2020_21, school: school, survey_item_responses << SurveyItemResponse.new(response_id: rand.to_s, academic_year: ay_2020_21, school: school, survey_item: survey_item, likert_score: 4)
survey_item: survey_item, likert_score: 4
end end
end end
SurveyItemResponse.import survey_item_responses
end end
scenario 'User authentication fails' do scenario 'User authentication fails' do

@ -11,15 +11,17 @@ describe SurveyItemResponse, type: :model do
let(:teacher_survey_item_2) { create(:survey_item, survey_item_id: 't-question-2', measure: measure) } let(:teacher_survey_item_2) { create(:survey_item, survey_item_id: 't-question-2', measure: measure) }
let(:teacher_survey_item_3) { create(:survey_item, survey_item_id: 't-question-3', measure: measure) } let(:teacher_survey_item_3) { create(:survey_item, survey_item_id: 't-question-3', measure: measure) }
context 'and there is sufficient teacher data' do context "and the number of responses for each of the measure's survey items meets the teacher threshold of 17" do
before :each do before :each do
4.times do 17.times do
create(:survey_item_response, survey_item: teacher_survey_item_1, academic_year: ay, school: school, likert_score: 3) create(:survey_item_response, survey_item: teacher_survey_item_1, academic_year: ay, school: school, likert_score: 3)
create(:survey_item_response, survey_item: teacher_survey_item_1, academic_year: ay, school: school, likert_score: 5)
create(:survey_item_response, survey_item: teacher_survey_item_2, academic_year: ay, school: school, likert_score: 3)
create(:survey_item_response, survey_item: teacher_survey_item_2, academic_year: ay, school: school, likert_score: 5)
end end
create(:survey_item_response, survey_item: teacher_survey_item_2, academic_year: ay, school: school, likert_score: 4) 17.times do
create(:survey_item_response, survey_item: teacher_survey_item_2, academic_year: ay, school: school, likert_score: 4)
end
17.times do
create(:survey_item_response, survey_item: teacher_survey_item_3, academic_year: ay, school: school, likert_score: 5)
end
end end
it 'returns the average of the likert scores of the survey items' do it 'returns the average of the likert scores of the survey items' do
@ -27,10 +29,53 @@ describe SurveyItemResponse, type: :model do
end end
end end
context 'and there is insufficient teacher data' do context "and the average number of responses across the measure's survey items meets the teacher threshold of 17" do
before :each do before :each do
(SurveyItemResponse::TEACHER_RESPONSE_THRESHOLD - 1).times do 19.times do
create(:survey_item_response, survey_item: teacher_survey_item_1, academic_year: ay, school: school) create(:survey_item_response, survey_item: teacher_survey_item_1, academic_year: ay, school: school, likert_score: 3)
end
16.times do
create(:survey_item_response, survey_item: teacher_survey_item_2, academic_year: ay, school: school, likert_score: 4)
end
16.times do
create(:survey_item_response, survey_item: teacher_survey_item_3, academic_year: ay, school: school, likert_score: 5)
end
end
it 'returns the average of the likert scores of the survey items' do
average_score = 3.941
expect(SurveyItemResponse.score_for_measure(measure: measure, school: school, academic_year: ay)).to be_within(0.001).of(average_score)
end
end
context "and none of the measure's survey items meets the teacher threshold of 17" do
before :each do
16.times do
create(:survey_item_response, survey_item: teacher_survey_item_1, academic_year: ay, school: school, likert_score: rand)
end
16.times do
create(:survey_item_response, survey_item: teacher_survey_item_2, academic_year: ay, school: school, likert_score: rand)
end
16.times do
create(:survey_item_response, survey_item: teacher_survey_item_3, academic_year: ay, school: school, likert_score: rand)
end
end
it 'returns nil' do
expect(SurveyItemResponse.score_for_measure(measure: measure, school: school, academic_year: ay)).to be_nil
end
end
context "and the average number of responses across the measure's survey items does not meet the teacher threshold of 17" do
before :each do
18.times do
create(:survey_item_response, survey_item: teacher_survey_item_1, academic_year: ay, school: school, likert_score: rand)
end
16.times do
create(:survey_item_response, survey_item: teacher_survey_item_2, academic_year: ay, school: school, likert_score: rand)
end
16.times do
create(:survey_item_response, survey_item: teacher_survey_item_3, academic_year: ay, school: school, likert_score: rand)
end end
end end
@ -43,26 +88,73 @@ describe SurveyItemResponse, type: :model do
context 'when the measure includes only student data' do context 'when the measure includes only student data' do
let(:student_survey_item_1) { create(:survey_item, survey_item_id: 's-question-1', measure: measure) } let(:student_survey_item_1) { create(:survey_item, survey_item_id: 's-question-1', measure: measure) }
let(:student_survey_item_2) { create(:survey_item, survey_item_id: 's-question-2', measure: measure) } let(:student_survey_item_2) { create(:survey_item, survey_item_id: 's-question-2', measure: measure) }
let(:student_survey_item_3) { create(:survey_item, survey_item_id: 's-question-3', measure: measure) }
context 'and there is sufficient student data' do context "and the number of responses for each of the measure's survey items meets the student threshold of 196" do
before :each do before :each do
(SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD/4).times do 196.times do
create(:survey_item_response, survey_item: student_survey_item_1, academic_year: ay, school: school, likert_score: 1) create(:survey_item_response, survey_item: student_survey_item_1, academic_year: ay, school: school, likert_score: 3)
create(:survey_item_response, survey_item: student_survey_item_1, academic_year: ay, school: school, likert_score: 5) end
create(:survey_item_response, survey_item: student_survey_item_2, academic_year: ay, school: school, likert_score: 1) 196.times do
create(:survey_item_response, survey_item: student_survey_item_2, academic_year: ay, school: school, likert_score: 5) create(:survey_item_response, survey_item: student_survey_item_2, academic_year: ay, school: school, likert_score: 4)
end
196.times do
create(:survey_item_response, survey_item: student_survey_item_3, academic_year: ay, school: school, likert_score: 5)
end end
end end
it 'returns the average of the likert scores of the survey items' do it 'returns the average of the likert scores of the survey items' do
expect(SurveyItemResponse.score_for_measure(measure: measure, school: school, academic_year: ay)).to eq 3 expect(SurveyItemResponse.score_for_measure(measure: measure, school: school, academic_year: ay)).to eq 4
end end
end end
context 'and there insufficient student data' do context "and the average number of responses across the measure's survey items meets the student threshold of 196" do
before :each do before :each do
(SurveyItemResponse::STUDENT_RESPONSE_THRESHOLD - 1).times do 200.times do
create(:survey_item_response, survey_item: student_survey_item_1, academic_year: ay, school: school) create(:survey_item_response, survey_item: student_survey_item_1, academic_year: ay, school: school, likert_score: 3)
end
195.times do
create(:survey_item_response, survey_item: student_survey_item_2, academic_year: ay, school: school, likert_score: 4)
end
193.times do
create(:survey_item_response, survey_item: student_survey_item_3, academic_year: ay, school: school, likert_score: 5)
end
end
it 'returns the average of the likert scores of the survey items' do
average_score = 3.988
expect(SurveyItemResponse.score_for_measure(measure: measure, school: school, academic_year: ay)).to be_within(0.001).of(average_score)
end
end
context "and none of the measure's survey items meets the student threshold of 196" do
before :each do
195.times do
create(:survey_item_response, survey_item: student_survey_item_1, academic_year: ay, school: school, likert_score: rand)
end
195.times do
create(:survey_item_response, survey_item: student_survey_item_2, academic_year: ay, school: school, likert_score: rand)
end
195.times do
create(:survey_item_response, survey_item: student_survey_item_3, academic_year: ay, school: school, likert_score: rand)
end
end
it 'returns nil' do
expect(SurveyItemResponse.score_for_measure(measure: measure, school: school, academic_year: ay)).to be_nil
end
end
context "and the average number of responses across the measure's survey items does not meet the student threshold of 196" do
before :each do
200.times do
create(:survey_item_response, survey_item: student_survey_item_1, academic_year: ay, school: school, likert_score: rand)
end
196.times do
create(:survey_item_response, survey_item: student_survey_item_2, academic_year: ay, school: school, likert_score: rand)
end
191.times do
create(:survey_item_response, survey_item: student_survey_item_3, academic_year: ay, school: school, likert_score: rand)
end end
end end

Loading…
Cancel
Save